# 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` 70000–79999) 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 ``` - 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`: ```json { "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 ``` - 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: ``` - 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). ```json { "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 ``` --- ## 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: ```json "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 `` 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.