Files
Remote-Poster/docs/polaris-papi-reference.md
2026-07-09 14:41:31 -04:00

11 KiB
Raw Permalink Blame History

Polaris.ApplicationServices (PAPI) API Reference

Source: Osceola Library System's Polaris.ApplicationServices help docs (https://osceola.librarycatalog.info/polaris.applicationservices/help/...) Compiled for internal reference to support scripting against the Notices endpoint.


1. The API — Basics

  • Base API version: v1 (only supported version)
  • Status check URL: https://[your server name]/Polaris.ApplicationServices/api Returns a JSON blob with ServiceName, Version, Major, Minor, Build, Revision.

URI structure

All URIs (other than API status and staff authentication) include these route segments, in order:

/api/{version}/{language}/{productId}/{siteDomain}/{organizationId}/{workstationId}/...
Segment Type Required Notes
version string Yes "v1"
language string Yes ISO 639-2 code — eng, spa, fre, chi, ara, fas, hat, haw, kor, rus, vie, etc.
productId integer Yes See product ID table below
siteDomain string Yes Customer site domain (default is "polaris")
organizationId integer Yes Logged-on organization ID
workstationId integer Yes Logged-on workstation ID

Example full URI:

/api/v1/eng/19/polaris/1/1/patrons/{id}/basicdata

Docs often show this in shorthand as /api/.../patrons/{id}/basicdata.

Product IDs

Value Product
0 All
1 PowerPAC
2 ChildrensPAC
3 ActivePAC
4 ExpressCheck
5 InboundTelephony
6 OutboundTelephony
7 Notices
8 ILL
9 PolarisFusion
10 AcquisitionsExchange
11 MobilePAC
12 SIPService
13 NCIPService
14 ERMSPortal
15 Receipts
16 ContentXChange
17 PolarisImport
18 PolarisAPIConsumerService
19 PolarisApplicationServices
20 StaffWebClient
21 StaffClient
22 PolarisDatabase
23 SystemOutput
24 Vega

Since we're calling the Notices endpoint, productId = 7 (Notices) is likely the semantically "correct" one to use, though 19 (PolarisApplicationServices) may also work depending on how the server is configured — worth confirming against a working example if you have one.

HTTP response codes

Code Status Notes
200 OK Success
201 Created Returns created object
204 No Content Successful deletion
400 Bad Request Validation errors, malformed params, etc. Body includes Message/MessageDetail, sometimes ErrorCode.
401 Unauthorized {"ErrorCode":10001,"Message":"User authentication failed."}
403 Forbidden Permission not granted; response includes override info (see Security section)
404 Not Found Either "no matching route" or "record not found" (e.g. ErrorCode 60027)
405 Method Not Allowed Wrong HTTP verb for the resource
409 Conflict Object lock (ErrorCode 7000079999) or secured record (ErrorCode 10004)
411 Length Required Missing Content-Length
422 Unprocessable Entity Body isn't valid JSON
500+ Server Error Unhandled exception

2. Security and Authentication

Three supported auth mechanisms:

  1. HTTP Basic Authentication + Access Token/Secret (the standard flow)
  2. ASP.NET Forms Authentication (cookie-based, browser/JS clients on same domain)
  3. Bearer Token via OAuth2 (OpenID Connect + PKCE)

Plus: Proxy-Authorization for privilege overrides.

2.1 Basic Auth → Access Token/Secret (primary flow for scripting)

Step 1 — Call the staff auth endpoint with HTTP Basic Auth:

POST /api/.../authentication/staffuser
Authorization: Basic <base64(DOMAIN\username:password)>
  • Username must include the domain, e.g. MYLIB\Aladdin.
  • Combine as "DOMAIN\username:password", then base64-encode the whole string.
  • No request body.

Step 2 — Response contains an AccessToken and AccessSecret:

{
    "SiteDomain": "polaris",
    "UserDomain": "iii.com",
    "AccessToken": "NXmeihFv2kq6meg3EdYoenv2VagJrPHs",
    "AccessSecret": "odXCBZuhXBkbwSo4",
    "AuthExpDate": "2013-03-26T10:41:11.103",
    "PolarisUser": {
        "PolarisUserID": 923,
        "OrganizationID": 3,
        "Name": "Young",
        "BranchID": null,
        "Enabled": true,
        "CreatorID": 895,
        "ModifierID": null,
        "CreationDate": "2011-02-16T20:28:16.177",
        "ModificationDate": null
    },
    "ERMSNetworkAddress": "young-lt2.polarislibrary.com",
    "DataSource": "RD-POLARIS"
}

Step 3 — Use the token/secret on all subsequent calls, in a custom PAS auth scheme (not base64-encoded):

Authorization: PAS {siteDomain}:{AccessToken}:{AccessSecret}

Example:

Authorization: PAS polaris:NXmeihFv2kq6meg3EdYoenv2VagJrPHs:odXCBZuhXBkbwSo4

2.2 Bearer Token (OAuth2) variant of staff auth

POST /api/.../authentication/staffuser/oauth
Authorization: Bearer <JWT access token>
  • The JWT's upn claim must be username@domain format and match a Polaris staff user.
  • Response shape is identical to the Basic Auth flow (still returns AccessToken/AccessSecret to use for follow-on calls).

2.3 API Key Authentication (alternative, no token/secret round-trip)

POST /api/.../authentication/staffuser
x-api-key: <your API key>
  • No Authorization header — the key goes in the x-api-key header.
  • Response does not include AccessToken/AccessSecret (they're blank strings) — the API key itself is presumably reused directly on subsequent calls (docs don't show that call shape explicitly, so confirm against a working example).
{
  "SiteDomain": "",
  "UserDomain": "",
  "AccessToken": "",
  "AccessSecret": "",
  "AuthExpDate": null,
  "PolarisUser": {
    "PolarisUserID": 1,
    "OrganizationID": 5,
    "Name": "PolarisExec",
    "BranchID": null,
    "Enabled": true,
    "CreatorID": 1,
    "ModifierID": 1,
    "CreationDate": null,
    "ModificationDate": "2020-12-11T10:28:20.69-05:00"
  },
  "ERMSNetworkAddress": "clvitn-pc197yjl.polarislibrary.com",
  "DataSource": "CLVITN-PC197YJL",
  "SiteCode": "MIS/"
}

2.4 Privilege overrides (403 handling)

If a call returns 403 Forbidden because the authenticated user lacks a permission, you can supply override credentials via:

  • Proxy-Authorization header, or
  • Polaris-Override-Authorization custom header (supports multiple overrides per call)

Format (before base64 encoding):

username:password:permissionid:permissionownerid

Example:

Proxy-Authorization: Basic cG9sYXJpc2V4ZWNAZG9tYWluOnBhc3N3b3JkOjgzOjEwMw==

Multiple overrides via repeated headers or a comma-delimited list of Basic ... values in one header.

Note: the primary Authorization header (token/secret) is still required alongside any override header.


3. HTTP Headers Cheat Sheet

GET requests — set Accept:

Accept: application/json

(also valid: text/json, image/jpg for binary/image responses)

PATCH / POST / PUT requests — set Content-Type:

Content-Type: application/json

Auth headers:

Authorization: PAS {siteDomain}:{AccessToken}:{AccessSecret}
Proxy-Authorization: Basic <base64 override>

4. Notices — POST (the endpoint we care about)

Post notices to the database

POST /api/.../notices/post?noticeType={notificationtypeid}&deliveryOption={deliveryoptionid}

Query parameters

Name Type Required Description
noticeType integer Yes ID of the Notification Type
deliveryOption integer Yes ID of the Delivery Option. Only valid value is Mail (1).

Request body

A JSON string containing a comma-separated list of Organization IDs:

"3,5,7"

Response

Returns a plain boolean.

  • Success: true
  • Failure: false

HTTP response codes

Code Meaning
200 OK. Success
400 Failure — bad request, invalid noticeType, or invalid deliveryOption

Notes / open questions for implementation

  • The docs don't enumerate valid noticeType (Notification Type) IDs on this page — that's presumably in Polaris's system tables or the "System Administration" section elsewhere in the docs (e.g. Parameters and Profiles, or a lookup table). Worth checking the Polaris database (Polaris.SystemNotifications or similar) or asking the vendor if you need the full list.
  • deliveryOption is documented as only accepting 1 (Mail) right now, despite the API allowing an integer — so don't expect e.g. email/SMS options to work here even if other DeliveryOptions endpoints list more.
  • The response being a bare true/false (not an object) means your client code should parse the raw JSON boolean rather than expecting a structured object — easy to trip up if you assume every endpoint returns a DTO.
  • productId for this call is most likely 7 (Notices) per the product ID table — worth confirming with a test call.

5. Corrections confirmed against a live server (Osceola)

While building post_notices.py against Osceola's live Polaris.ApplicationServices instance, two things in this doc turned out to be wrong or incomplete:

  • Staff authentication URL is shorter than section 1 implies. The "all URIs other than API status and staff authentication" caveat in section 1 undersells how different the auth route is. It is not /api/{version}/{language}/{productId}/{siteDomain}/{organizationId}/{workstationId}/authentication/staffuser — it's just /api/{version}/{language}/{productId}/authentication/staffuser, with no siteDomain, organizationId, or workstationId segments at all. Calling the full-length URL returns a 404 with an empty body (a routing miss, not an app-level error — Polaris's real error responses come back as JSON with Message/ErrorCode). This exact URL shape isn't visible anywhere in the rendered help page text; it only shows up as a title="{version}/{language}/{productId}" attribute on the <span> wrapping the "..." in POST /api/.../authentication/staffuser, i.e. you have to view-source the page (polaris.applicationservices/help/authentication/post_staffuser) to find it — a plain fetch or rendered read of the page won't surface it.
  • productId = 19 (PolarisApplicationServices) is confirmed working end-to-end (auth + notices/post) against Osceola's server. productId = 7 (Notices) — this doc's original best guess — was not confirmed; it may still be correct, but wasn't tested.

6. Gaps in this doc (pages that returned no additional content)

Two pages in the doc set — Common Response Structures and Collections (both under "Introduction") — returned only their page heading with no body content when fetched. This might mean:

  • The content is loaded client-side via JavaScript that a simple page fetch won't execute, or
  • Those particular pages are thin/placeholder pages in this Polaris version.

If you need the actual content of those two pages (e.g. for handling paginated list responses in the notices or other endpoints), it may be worth viewing them directly in a browser to check whether there's dynamically-loaded content, since a plain HTTP fetch didn't surface anything under those headings.