Developers
API reference
Read access to a Cadence organization's clinical operations data, plus opt-in writes that schedule sessions and create or update authorizations. Every resource is scoped to the authenticated organization and keyed by an opaque `tokenRef`; protected health information - client names, note narratives - is never returned. Authenticate with `Authorization: Bearer <key>`. Each key carries read scopes (`clients`, `sessions`, `authorizations`, `notes`) and, optionally, write scopes (`sessions:write`, `authorizations:write`); writes are refused without one. Requests are limited to 120 requests per minute per key and per IP, enforced per serving instance; a 429 carries a `Retry-After` header. List endpoints page by keyset cursor (`?cursor=`) in `(createdAt DESC, id DESC)` order.
Getting started
Base URL: https://www.cadenceaba.com/api/v1. Authenticate every request with an organization API key (created in Settings → API, on the Practice plan):
curl "https://www.cadenceaba.com/api/v1/clients?limit=50" \ -H "Authorization: Bearer cad_sk_…" # next page curl "https://www.cadenceaba.com/api/v1/clients?cursor=<next_cursor>" \ -H "Authorization: Bearer cad_sk_…"
Responses are JSON and de-identified - clients are keyed by an opaque tokenRef, and PHI (names, note narratives) never leaves, in line with the safeguards on our HIPAA & BAA page. Requests are limited to 120 requests per minute per key and per IP, enforced per serving instance; a 429 carries a Retry-After header. Create endpoints accept an Idempotency-Key header so retries never duplicate. The full machine-readable contract lives at /api/v1/openapi.json.
Scopes
Each key carries a least-privilege set. Read scopes gate the corresponding GET resources; write scopes are opt-in and gate create/update. A key created before scoping existed reads everything and writes nothing.
clientsGET /clients and /clients/{id}sessionsGET /sessionsauthorizationsGET /authorizations and /authorizations/{id}notesGET /notesauthorizations:writePOST /authorizations and PATCH /authorizations/{id}sessions:writePOST /sessionsEndpoints
/api/v1Confirms the key works and lists the available resources plus the key's scopes. Requires any valid key - no specific scope.
Responses
200OK401Missing or invalid API key.403The key lacks the required scope, the organization's plan does not include API access, or the workspace has been closed.429Too many requests. Back off and retry after the `Retry-After` header's seconds.
/api/v1/clientsRequires the `clients` scope.
Parameters
limitquery · integerMaximum items to return (1-200). Defaults to 50.offsetquery · integerNumber of items to skip, for offset pagination. Ignored when a `cursor` is supplied.cursorquery · stringOpaque keyset cursor from a previous response's `next_cursor`. Preferred over `offset` - it's stable under concurrent inserts. Both paginate the same `(createdAt DESC, id DESC)` ordering.
Responses
200OK401Missing or invalid API key.403The key lacks the required scope, the organization's plan does not include API access, or the workspace has been closed.429Too many requests. Back off and retry after the `Retry-After` header's seconds.
/api/v1/clients/{id}Requires the `clients` scope.
Parameters
idpath · required · string <uuid>
Responses
200OK401Missing or invalid API key.403The key lacks the required scope, the organization's plan does not include API access, or the workspace has been closed.404No such resource in your organization.429Too many requests. Back off and retry after the `Retry-After` header's seconds.
/api/v1/sessionsRequires the `sessions` scope. A `cursor` that this API did not issue is rejected with 400 `invalid_request` rather than restarting from the first page.
Parameters
clientIdquery · string <uuid>Filter to a single client id. Intersected with your organization - a foreign id returns nothing.limitquery · integerMaximum items to return (1-200). Defaults to 50.offsetquery · integerNumber of items to skip, for offset pagination. Ignored when a `cursor` is supplied.cursorquery · stringOpaque keyset cursor from a previous response's `next_cursor`. Preferred over `offset` - it's stable under concurrent inserts. Both paginate the same `(createdAt DESC, id DESC)` ordering.
Responses
200OK401Missing or invalid API key.403The key lacks the required scope, the organization's plan does not include API access, or the workspace has been closed.429Too many requests. Back off and retry after the `Retry-After` header's seconds.
/api/v1/sessionsRequires the `sessions:write` scope. Creates a `scheduled` session (a calendar slot) - the client is referenced by id; no clinical capture data or direct patient identifiers are accepted. The slot is created unassigned and picked up by whoever starts it.
Parameters
Idempotency-Keyheader · stringMakes a create safe to retry. The first request with a given key is processed and its result stored; a retry with the same key and body replays that result instead of creating a duplicate. Reusing a key with a different body returns 409 `idempotency_key_reused`, and a retry that arrives while the first request is still running returns 409 `idempotency_in_progress`. Keys are remembered indefinitely, so a key can never be reused for a different operation. Keys are remembered for 24 hours; after that the same key starts a new request.
Request body - CreateSession
| Field | Type | Notes |
|---|---|---|
| clientIdreq | string <uuid> | A client in your organization. |
| scheduledStartreq | string <date-time> | |
| scheduledEnd | string <date-time> | Must be after scheduledStart. |
| cptCode | string | One of: 97151, 97152, 97153, 97154, 97155, 97156, 97157, 97158. |
| location | string · max 40 | A short place name such as "home", "clinic", or "telehealth". |
Responses
201Created400The request body is missing, malformed, or fails validation.401Missing or invalid API key.403The key lacks the required scope, the organization's plan does not include API access, or the workspace has been closed.404No such resource in your organization.409`duplicate_session`: the client already has a scheduled or in-progress session starting at exactly `scheduledStart` - the existing session's id is returned as `error.sessionId`. Also the `Idempotency-Key` conflicts (`idempotency_key_reused`, `idempotency_in_progress`) described under other write endpoints.429Too many requests. Back off and retry after the `Retry-After` header's seconds.
/api/v1/notesNote metadata only - the SOAP narrative is PHI and is never returned. Requires the `notes` scope.
Parameters
sessionIdquery · string <uuid>Filter notes to a single session id.limitquery · integerMaximum items to return (1-200). Defaults to 50.offsetquery · integerNumber of items to skip, for offset pagination. Ignored when a `cursor` is supplied.cursorquery · stringOpaque keyset cursor from a previous response's `next_cursor`. Preferred over `offset` - it's stable under concurrent inserts. Both paginate the same `(createdAt DESC, id DESC)` ordering.
Responses
200OK400The request body is missing, malformed, or fails validation.401Missing or invalid API key.403The key lacks the required scope, the organization's plan does not include API access, or the workspace has been closed.429Too many requests. Back off and retry after the `Retry-After` header's seconds.
Pagination & errors
Every list endpoint returns { object: "list", data: [...], has_more, next_cursor }. Pass next_cursor back as ?cursor= to fetch the next page; it is a keyset cursor, so rows inserted while you page are never skipped or repeated. Single resources return { object, data }.
Every non-2xx response carries one envelope. The code is stable and safe to branch on; the message is for people and may change.
Error.error
| Field | Type | Notes |
|---|---|---|
| codereq | string | A stable, machine-readable reason. One of: unauthorized, invalid_key, plan_required, workspace_closed, insufficient_scope, rate_limited, not_found, client_not_found, invalid_json, invalid_request, idempotency_in_progress, idempotency_key_reused, duplicate_session. |
| messagereq | string | A human-readable explanation; wording may change. |
| sessionId | string <uuid> | Only on `duplicate_session`: the id of the session that already occupies the slot. |
Resource shapes
Client
| Field | Type | Notes |
|---|---|---|
| idreq | string <uuid> | |
| tokenRefreq | string | Opaque, de-identified client reference (never PHI). |
| statusreq | string | One of: active, inactive, discharged. |
| clinicIdreq | string <uuid> | |
| createdAtreq | string <date-time> |
Session
| Field | Type | Notes |
|---|---|---|
| idreq | string <uuid> | |
| clientIdreq | string <uuid> | |
| clinicIdreq | string <uuid> | |
| statusreq | string | One of: scheduled, in_progress, capture_complete, note_drafted, signed, billed, canceled, no_show. |
| cptCode | string | null | Planned CPT code. |
| location | string | null | |
| scheduledStart | string | null <date-time> | |
| scheduledEnd | string | null <date-time> | |
| startedAt | string | null <date-time> | |
| endedAt | string | null <date-time> | |
| createdAtreq | string <date-time> |
Note
| Field | Type | Notes |
|---|---|---|
| idreq | string <uuid> | |
| sessionIdreq | string <uuid> | |
| clientIdreq | string <uuid> | |
| statusreq | string | One of: draft, pending_signature, signed, amended. |
| formatreq | string | |
| signedAt | string | null <date-time> | |
| signedByUserId | string | null <uuid> | |
| createdAtreq | string <date-time> |