Initial commit
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
# 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 <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`:
|
||||
|
||||
```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 <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).
|
||||
|
||||
```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 <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:
|
||||
|
||||
```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 `<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.
|
||||
Reference in New Issue
Block a user