# ALIS API Reference (for the `alis` skill) Source of truth: the live Swagger specs the ALIS API publishes. - Swagger UI: https://api.alisonline.com/index.html - Raw specs: `https://api.alisonline.com/specs/v1/openapi.json` (also `v2`, `v3`) - Vendor docs (gated, requires support login): https://support.alisonline.com/ ALIS = Medtelligent's assisted-living EHR. The API is a **partner/App-Store integration API**. A tenant lives at `.alisonline.com` (e.g. `cascadestucson.alisonline.com`) but **all API traffic goes to the shared host `api.alisonline.com`**, scoped by the logged-in user's company + a `communityId`. Spec sizes at build (2026-06-29): v1 = 139 paths (main surface), v2 = 14 (newer streaming exports + incidents), v3 = 5 (streaming exports). Tags: User (auth), Admin, Export:*, Integration:* (Billing/Care/Communities/Residents/Staff/Prospects/Incidents/Hooks/App Specific), Pharmacy. ## Authentication Global security is an OR list: `Bearer | BasicAuth | VendorKey` — any one authorizes. - **Bearer (what this skill uses):** - `POST /user/tokens` body `{"username":"@","password":"..."}` → `{ accessToken (JWT, expiresIn 3600), refreshToken }` - `POST /user/tokens/refresh` body `{accessToken, refreshToken}` → new pair - Send `Authorization: Bearer ` on every call. - **The username MUST be tenant-qualified.** `howard.enos` → HTTP 400 (`Username must match ^@$`); `howard.enos@cascadestucson` → 200. tenantKey = the tenant subdomain (`cascadestucson`). - **VendorKey:** `X-Vendor-Key: ` header — issued by Medtelligent when an App-Store app is installed (per-client creds). Not required when a user JWT is used. - **BasicAuth:** `Authorization: Basic ...` — the existing `clients/cascades-tucson/alis-api-microsoft-basic` vault entry is this style (used by Microsoft to call ALIS). ## Staff endpoints — READ ONLY (this is the key constraint) There is **no** POST/PUT/PATCH/DELETE for staff anywhere in v1/v2/v3. All six are GET: | Method | Path | Returns | |---|---|---| | GET | `/v1/integration/staff?communityId={id}` | roster (communityId REQUIRED — omitting → 403 "Not authorized for facility 0") | | GET | `/v1/integration/staff/{staffId}` | one staff member | | GET | `/v1/integration/staff/{staffId}/basicInfo` | address, license, jobRole, **securityRoles** | | GET | `/v1/integration/staff/{staffId}/photo` | photo | | GET | `/v1/export/staff` | bulk export | | GET | `/v1/export/staff/complianceDetails` | training/compliance | Staff list record fields: `staffId, companyTextKey, communityId, firstName, lastName, nickName, staffRecordNumber, mobilePhoneNumber, primaryEmail, dateOfBirth, status, hireDate, dischargeDate, hasPhoto, jobRole, securityRoles[]`. Optional query params on the list: `status`, `includeAssociatedStaff`. **To CHANGE staff** → there is no API. Use the ALIS web UI **Staff → Import** with the 13-column .xls (see `import_builder.py` / SKILL.md). That import sets `Login Enabled` and `Password`, i.e. it is also how staff *logins* are provisioned. ## Other write surfaces (out of scope for this skill, but available on the JWT) The API *does* allow writes for non-staff objects, e.g.: - Residents: `POST /v1/integration/residents` (create), `POST .../{residentId}/basicInfo`, contacts, photo, observations, vitals, room assignments, diagnoses, monitoring flags. - Prospects (CRM): `POST/PUT /v1/integration/prospects...` - Billing: incidental charges, payments, statements. - Webhooks: `/v1/integration/hooks` (subscribe to object create/modify events). ## Scope observed (Cascades, communityId 622, build 2026-06-29) - 1 community: 622 = "Cascades of Tucson". - 612 staff total (504 Discharged, 107 Hired, 1 Observer). - 23 distinct Security Roles in use; 74 distinct Job Role strings (free text — includes typos/dupes like `caregiver` vs `Certified Caregiver`, and junk like `Test`, `Dead Weight` — treat Job Role as free text, Security Roles as the controlled list). - See `role-map.json` for the snapshot + job-role → security-role mapping.