Integrating a third-party product¶
The platform exposes two integration modes. Both authenticate with OAuth2 client credentials and share the same endpoint surface; the difference is whether your code calls the HTTP API directly or goes through the official TypeScript SDK.
Acting on behalf of a clinician? See token-exchange.md. When a real human (signed in via AWS Cognito) triggered the request, you can swap their Cognito ID token for a short-lived delegated platform token whose audit entries record the human, not your service account.
High-trust integration that needs cert-based auth? See mtls.md. Optional opt-in to OAuth2 mTLS (RFC 8705) — present a registered X.509 client cert in place of
client_secret. Issued tokens carry acnf.x5t#S256binding so resource servers can verify the same cert presented the request.Granting broad access without enumerating every scope? Scopes may contain wildcards:
cases:*covers everycases:<action>scope (read, write, archive, etc.) and*covers everything. See scopes.md.
Quick comparison¶
| Direct API | SDK | |
|---|---|---|
| Transport | You make HTTPS calls | You call typed TS methods, SDK handles HTTPS |
| Token refresh | You manage | SDK caches + refreshes 30s before expiry |
| Language | Any | TypeScript / JavaScript (Node 20+) |
| Scope enforcement | Server-side (403 on missing scope) | Server-side (same; the SDK doesn't pre-filter) |
| Workflows endpoints | Available with orchestrator:* scopes |
Same — client.workflows.* methods |
| Best for | Existing products in any language, custom HTTP needs | New TypeScript integrations, fastest path to working code |
Both modes hit the same endpoints in the catalogue below. The admin Integration tab (/orgs/:orgId/products/:productId/integration) is the easiest place to copy the parameters for either mode — open it for the specific (organisation, product) you're integrating against.
Get credentials¶
Each integration is provisioned as an OAuth2 client (client_id + client_secret) scoped to a single organisation + product. Ask the platform operator for:
client_idclient_secret- The list of granted scopes (see catalogue)
- The platform host (e.g.
https://api.example.com) — the platform serves every service under a single host using per-service path prefixes (/v1/clinical-api/...,/v1/orchestrator/...,/v1/auth/...). The Direct API and SDK examples below show how the prefixes are composed.
Mode 1 — Direct API¶
See direct-api.md for the full walkthrough. Three steps:
- Exchange your client credentials for a short-lived access token (
POST /v1/auth/oauth/tokenon the auth service). - Call any endpoint in your scope set with
Authorization: Bearer <access_token>. - Re-issue the token on expiry (~1h).
Mode 2 — SDK¶
See sdk.md for the install + first-call walkthrough. One step:
npm install @sa-platform/client-sdk
import { SkinAnalyticsClient } from '@sa-platform/client-sdk';
const client = new SkinAnalyticsClient({
baseUrl, // platform host root, e.g. https://platform.example.com
clientId,
clientSecret,
scopes: ['cases:write', 'patients:write', 'images:write'],
});
const patient = await client.patients.create({
given_name: 'Alice',
family_name: 'Anderson',
dob: '1985-06-15',
});
const c = await client.cases.create({ patient_id: patient.id as string });
Postman collection¶
The Integration tab offers two downloads side-by-side:
- Download Postman collection — a Postman v2.1 collection scoped to the (org, product) and to the scopes you ticked. The first folder,
0. Auth — get an access token, is the OAuth2 client-credentials request; the remaining folders are grouped by category (Patients, Cases, Images, Workflows, AI Review, Webhooks). - Download environment — a paired Postman v2.1 environment that pre-fills
baseUrl(your platform host root) andclientId.clientSecretandaccessTokenship empty; Postman masks both astype: "secret"so they don't leak when you screen-share.
Workflow:
- Import the collection and the environment.
- Select the environment in Postman's top-right environment picker.
- Open the environment and paste your
client_secret(from the credentials tab — we never ship secrets in the downloaded file). - Run
0. Auth → POST /v1/auth/oauth/tokenand copy theaccess_tokenresponse field into the environment'saccessTokenvariable. - Call any request in the remaining folders — they all resolve against
{{baseUrl}}<absolute-path>, where the path includes the per-service prefix (/v1/clinical-api/cases,/v1/orchestrator/workflow-instances/:id, etc.). Re-issue the token on expiry (~1 h).
Refreshing the download after routing changes¶
The collection is generated from services/admin-api/src/integrations/endpoint-catalogue.ts at request time. If endpoints have moved (e.g. the 2026-05-27 service-routing convention changed /v1/cases to /v1/clinical-api/cases), simply re-download — there is no file to refresh locally and no manual edit step. Old collections downloaded before the change continue to point at the old paths; throw them away and grab a fresh one from the Integration tab.
Catalogue¶
The full endpoint catalogue is rendered live in the Integration tab. As of 2026-06-02 it covers:
- Assessments — create, submit, get a consolidated AI assessment (
assessments:read/assessments:write). See consolidated-assessments.md for the full walkthrough including inline and slot image modes. - Patients — create, get, update (
patients:read/patients:write) - Cases — create, get, update (
cases:read/cases:write) - Images — upload, get (
images:read/images:write) - Workflows — fetch definition, fetch + advance instance (
orchestrator:read,orchestrator:read-instances,orchestrator:advance-instance) - AI Review — submit + poll DERM reviews (
derm_review:read/derm_review:write) - Webhooks — subscribe to + list event subscriptions (
webhooks:read/webhooks:write)
When new endpoints become integration-ready, they're added to services/admin-api/src/integrations/endpoint-catalogue.ts and surface immediately in the UI + Postman download.