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 (`insufficient_scope`), the organization's plan does not include API access (`plan_required`), the workspace has been closed (`workspace_closed`), or the subscription was never started (`subscription_required`). A write to an organization whose subscription has lapsed is refused with `read_only` - reads keep working.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
200OK400The request body is missing, malformed, or fails validation.401Missing or invalid API key.403The key lacks the required scope (`insufficient_scope`), the organization's plan does not include API access (`plan_required`), the workspace has been closed (`workspace_closed`), or the subscription was never started (`subscription_required`). A write to an organization whose subscription has lapsed is refused with `read_only` - reads keep working.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 (`insufficient_scope`), the organization's plan does not include API access (`plan_required`), the workspace has been closed (`workspace_closed`), or the subscription was never started (`subscription_required`). A write to an organization whose subscription has lapsed is refused with `read_only` - reads keep working.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
200OK400The request body is missing, malformed, or fails validation.401Missing or invalid API key.403The key lacks the required scope (`insufficient_scope`), the organization's plan does not include API access (`plan_required`), the workspace has been closed (`workspace_closed`), or the subscription was never started (`subscription_required`). A write to an organization whose subscription has lapsed is refused with `read_only` - reads keep working.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 for 24 hours; after that the same key starts a new request. A key longer than 255 characters is rejected with 400 `invalid_request`.
Request body - CreateSession
| Field | Type | Notes |
|---|---|---|
| clientIdrequired | string <uuid> | A client in your organization. |
| scheduledStartrequired | 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 (`insufficient_scope`), the organization's plan does not include API access (`plan_required`), the workspace has been closed (`workspace_closed`), or the subscription was never started (`subscription_required`). A write to an organization whose subscription has lapsed is refused with `read_only` - reads keep working.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`. `client_inactive`: the client is inactive or discharged, so no session can be booked for them. 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 (`insufficient_scope`), the organization's plan does not include API access (`plan_required`), the workspace has been closed (`workspace_closed`), or the subscription was never started (`subscription_required`). A write to an organization whose subscription has lapsed is refused with `read_only` - reads keep working.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 |
|---|---|---|
| coderequired | string | A stable, machine-readable reason. One of: unauthorized, invalid_key, plan_required, workspace_closed, subscription_required, insufficient_scope, read_only, rate_limited, not_found, client_not_found, client_inactive, invalid_json, invalid_request, idempotency_in_progress, idempotency_key_reused, duplicate_session. |
| messagerequired | 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 |
|---|---|---|
| idrequired | string <uuid> | |
| tokenRefrequired | string | Opaque, de-identified client reference (never PHI). |
| statusrequired | string | One of: active, inactive, discharged. |
| clinicIdrequired | string <uuid> | |
| createdAtrequired | string <date-time> |
Session
| Field | Type | Notes |
|---|---|---|
| idrequired | string <uuid> | |
| clientIdrequired | string <uuid> | |
| clinicIdrequired | string <uuid> | |
| statusrequired | 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> | |
| createdAtrequired | string <date-time> |
Note
| Field | Type | Notes |
|---|---|---|
| idrequired | string <uuid> | |
| sessionIdrequired | string <uuid> | |
| clientIdrequired | string <uuid> | |
| statusrequired | string | One of: draft, pending_signature, signed, amended. |
| formatrequired | string | |
| signedAt | string | null <date-time> | |
| signedByUserId | string | null <uuid> | |
| createdAtrequired | string <date-time> |