For the complete documentation index, see llms.txt. This page is also available as Markdown.

Sessions

List and retrieve provider-owned clinical documentation sessions with lifecycle state and transcript, note, summary, and coding artifact availability.

Sessions represent provider-owned clinical documentation encounters. Each session tracks its mode, lifecycle status, and artifact availability. Use the Scribe API base URL assigned to your deployment; these are not the Platform text-session WebSocket routes.

Read operations require scribe:sessions:read_own. Creating, updating, ending, cancelling, and controlling Zoom sessions require scribe:sessions:write, in addition to provider ownership and workspace access.

Scribe has its own public OpenAPI schema and provider access boundary. Use the Scribe HTTP Reference for canonical operation contracts and Capture to Finalized Note for the complete workflow. Use the Scribe deployment base assigned to your integration, separately from Platform text sessions.

Session Object

Read the session schema in Get Session. Session lifecycle, capture mode, and individual artifact readiness describe different parts of the encounter.

Artifact Availability

The artifacts object reports readiness for each artifact. Inspect the artifact's own generation state before displaying a note or concluding that generation completed.

List Sessions

List Sessions

get
Path parameters
workspace_idstring · uuidRequired
Query parameters
limitinteger · min: 1 · max: 200OptionalDefault: 50
continuation_tokenanyOptional
created_afterstring · date-time · nullableOptional
created_beforestring · date-time · nullableOptional
Responses
200

Successful Response

application/json
has_morebooleanRequired
continuation_tokenanyOptional
get/v1/{workspace_id}/sessions
GET /v1/{workspace_id}/sessions HTTP/1.1
Accept: */*
{
  "items": [
    {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "status": "in-progress",
      "mode": "in_person",
      "external_appointment_id": "text",
      "first_name": "text",
      "last_name": "text",
      "visit_type": "text",
      "note_template": "amd-psych-intake",
      "started_at": "2026-01-01T00:00:00.000Z",
      "ended_at": "2026-01-01T00:00:00.000Z",
      "created_at": "2026-01-01T00:00:00.000Z",
      "updated_at": "2026-01-01T00:00:00.000Z",
      "local_timezone": "text",
      "artifacts": {
        "transcript": "pending",
        "note": "pending",
        "summary": "pending",
        "codes": "pending"
      }
    }
  ],
  "has_more": true,
  "continuation_token": null
}

Returns a paginated list of sessions owned by the authenticated provider, ordered by creation time (newest first).

Query Parameters

Use the limit and continuation token in List Sessions; pass the returned continuation token unchanged for the next page.

Response

Use the session items and pagination fields rendered in List Sessions.

Example Request

Example Response

Get Session

Returns a single session owned by the authenticated provider.

Path Parameters

Use the matching workspace and the provider-owned session identifier in Get Session.

Response

Returns a session object (see schema above).

Errors

Status
Code
Description

404

not_found

Session does not exist or is not owned by the authenticated provider

Cancelled sessions are excluded from list results. The list sessions endpoint does not return sessions with a cancelled status. Cancelled sessions are also excluded when resolving the current session for an appointment. An appointment whose only sessions are cancelled appears with no linked session, the same as an appointment that has never had a session started.

Create an In-Person Session

Create Session

post
Path parameters
workspace_idstring · uuidRequired
Body
external_appointment_idstring · max: 512 · nullableOptional
external_idstring · max: 512 · nullableOptional
modestring · enumOptionalDefault: in_personPossible values:
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · enum · nullableOptionalPossible values:
note_templatestring · enum · nullableOptionalPossible values:
timezonestring · enum · min: 1RequiredPossible values:
Responses
201

Successful Response

application/json
idstring · uuidRequired
statusstring · enumRequiredPossible values:
modestring · enumRequired

Modality of a scribe session: an in-person ("mic") recording or a Zoom meeting.

Possible values:
external_appointment_idstring · max: 512 · nullableOptional
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · max: 256 · nullableOptional
note_templatestring · enum · nullableOptionalPossible values:
started_atstring · date-time · nullableRequired
ended_atstring · date-time · nullableRequired
created_atstring · date-timeRequired
updated_atstring · date-timeRequired
local_timezonestring · max: 64Required
post/v1/{workspace_id}/sessions
POST /v1/{workspace_id}/sessions HTTP/1.1
Content-Type: application/json
Accept: */*
Content-Length: 254

{
  "external_appointment_id": "text",
  "external_id": "text",
  "mode": "in_person",
  "metadata": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "first_name": "text",
  "last_name": "text",
  "visit_type": "psych-intake",
  "note_template": "amd-psych-intake",
  "timezone": "Africa/Abidjan"
}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "in-progress",
  "mode": "in_person",
  "external_appointment_id": "text",
  "first_name": "text",
  "last_name": "text",
  "visit_type": "text",
  "note_template": "amd-psych-intake",
  "started_at": "2026-01-01T00:00:00.000Z",
  "ended_at": "2026-01-01T00:00:00.000Z",
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-01-01T00:00:00.000Z",
  "local_timezone": "text",
  "artifacts": {
    "transcript": "pending",
    "note": "pending",
    "summary": "pending",
    "codes": "pending"
  }
}

Create a provider-owned microphone session. The general create route accepts only in_person mode. Supply a canonical visit_type; the service resolves and pins the corresponding supported note template. A supplied note_template must match. A missing visit type returns 422 note_template_required. An unrecognized visit_type or note_template value fails request validation with 422 validation_error, and a note_template that does not match the visit type returns 422 unsupported_note_template. No session is created in either case. The former generic templates (full, medical, soap, dap, birp) and the medical visit type are no longer accepted.

Each supported visit type has a telehealth and an in-person template variant (the -ip identifiers). When the session links to an appointment whose modality is known, that modality selects the variant, whatever the capture method. Otherwise an in-person session gets the in-person variant and a Zoom session gets the telehealth one. A supplied note_template can be the resolved template or its telehealth base, and the service pins the variant it resolved. Read note_template on the returned session for the pinned value.

Send timezone on every create: the provider's IANA time zone name, such as America/New_York. It is required on this route and on Create a Zoom Session; a missing or unrecognized zone returns 422. The session's local_timezone records the zone used for its local times and dates, for example in a configured EHR writeback. It is the supplied timezone unless the session links to an appointment whose own time zone can be resolved. Clients generated from an older schema must add this field.

The request also supports patient display-name fields, an optional appointment reference, metadata, and external_id for idempotency. Inspect the assigned Scribe schema for field constraints. A successful create returns the session with HTTP 201. Recording attachment and artifact generation are separate operations.

Session Mode

Every session carries a mode that indicates the session modality:

Value
Description

in_person

An in-person microphone recording (default).

zoom

A Zoom meeting session. A practitioner may have at most one non-terminal Zoom session at a time within a workspace.

The mode is fixed at creation. The general create-session route accepts in_person; use POST /v1/{workspace_id}/zoom/sessions for a Zoom session. PATCH does not change the mode.

Session Lifecycle

In-person (mic) sessions. In-person mic sessions now automatically receive post-visit note generation when they reach the review stage. Note generation is asynchronous. Inspect artifact availability separately from the session transition.

A session is in-progress from creation; there is no separate created state. Sessions support explicit REST transitions in addition to streaming-driven state changes:

Transition
Endpoint
From States
To State
Notes

End

POST /v1/{workspace_id}/sessions/{session_id}/end

in-progress

in-review

Refused with 409 session_streaming while a streaming worker is attached.

Cancel

POST /v1/{workspace_id}/sessions/{session_id}/cancel

in-progress, in-review

cancelled

Compensation and abort path. Terminal sessions return 409 invalid_session_state.

End Session

post

End an owned session (created/in-progress -> in-review), guarded against a live stream.

Mic race guard (§3A.2): while a streaming worker is attached the WS worker is the sole finalizer, so REST end returns 409 session_streaming and never touches transcript artifacts. Permitted only for an abandoned/never-streamed session; the guarded flip cannot race the worker or reaper.

Path parameters
workspace_idstring · uuidRequired
session_idstring · uuidRequired
Responses
200

Successful Response

application/json
idstring · uuidRequired
statusstring · enumRequiredPossible values:
modestring · enumRequired

Modality of a scribe session: an in-person ("mic") recording or a Zoom meeting.

Possible values:
external_appointment_idstring · max: 512 · nullableOptional
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · max: 256 · nullableOptional
note_templatestring · enum · nullableOptionalPossible values:
started_atstring · date-time · nullableRequired
ended_atstring · date-time · nullableRequired
created_atstring · date-timeRequired
updated_atstring · date-timeRequired
local_timezonestring · max: 64Required
post/v1/{workspace_id}/sessions/{session_id}/end
POST /v1/{workspace_id}/sessions/{session_id}/end HTTP/1.1
Accept: */*
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "in-progress",
  "mode": "in_person",
  "external_appointment_id": "text",
  "first_name": "text",
  "last_name": "text",
  "visit_type": "text",
  "note_template": "amd-psych-intake",
  "started_at": "2026-01-01T00:00:00.000Z",
  "ended_at": "2026-01-01T00:00:00.000Z",
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-01-01T00:00:00.000Z",
  "local_timezone": "text",
  "artifacts": {
    "transcript": "pending",
    "note": "pending",
    "summary": "pending",
    "codes": "pending"
  }
}

Cancel Session

post

Cancel an owned non-terminal session (-> cancelled); the saga-compensation / abort path.

Guarded so a terminal session no-ops with 409 invalid_session_state. Touches only status, never transcript artifacts.

Path parameters
workspace_idstring · uuidRequired
session_idstring · uuidRequired
Responses
200

Successful Response

application/json
idstring · uuidRequired
statusstring · enumRequiredPossible values:
modestring · enumRequired

Modality of a scribe session: an in-person ("mic") recording or a Zoom meeting.

Possible values:
external_appointment_idstring · max: 512 · nullableOptional
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · max: 256 · nullableOptional
note_templatestring · enum · nullableOptionalPossible values:
started_atstring · date-time · nullableRequired
ended_atstring · date-time · nullableRequired
created_atstring · date-timeRequired
updated_atstring · date-timeRequired
local_timezonestring · max: 64Required
post/v1/{workspace_id}/sessions/{session_id}/cancel
POST /v1/{workspace_id}/sessions/{session_id}/cancel HTTP/1.1
Accept: */*
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "in-progress",
  "mode": "in_person",
  "external_appointment_id": "text",
  "first_name": "text",
  "last_name": "text",
  "visit_type": "text",
  "note_template": "amd-psych-intake",
  "started_at": "2026-01-01T00:00:00.000Z",
  "ended_at": "2026-01-01T00:00:00.000Z",
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-01-01T00:00:00.000Z",
  "local_timezone": "text",
  "artifacts": {
    "transcript": "pending",
    "note": "pending",
    "summary": "pending",
    "codes": "pending"
  }
}

Update Session

Update Session

patch

Patch an owned session's mutable fields (external_appointment_id / metadata).

Idempotent; only fields present in the body are written (sending external_appointment_id: null clears the link). A session's mode is fixed at create and is not a field on UpdateSessionRequest, so PATCH cannot flip a session to zoom (that would mint a bot-less Zoom session that never went through the saga at POST /zoom/sessions — the 5dca2633 failure class). Returns the full refreshed session so callers see accurate artifact availability.

Path parameters
workspace_idstring · uuidRequired
session_idstring · uuidRequired
Body

Mutable fields for PATCH /sessions/{id}. Only fields present in the body are updated.

A session's mode is fixed at create — it is deliberately NOT a field here, so PATCH cannot flip a session to zoom (which would mint a bot-less Zoom session that never went through the saga — the 5dca2633 failure class). A Zoom session is created via POST /v1/{workspace_id}/zoom/sessions. external_appointment_id is explicitly nullable — sending null clears the link — so the route distinguishes "field omitted" (leave as-is) from "field set to null" via exclude_unset.

external_appointment_idstring · max: 512 · nullableOptional
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · enum · nullableOptionalPossible values:
note_templatestring · enum · nullableOptionalPossible values:
Responses
200

Successful Response

application/json
idstring · uuidRequired
statusstring · enumRequiredPossible values:
modestring · enumRequired

Modality of a scribe session: an in-person ("mic") recording or a Zoom meeting.

Possible values:
external_appointment_idstring · max: 512 · nullableOptional
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · max: 256 · nullableOptional
note_templatestring · enum · nullableOptionalPossible values:
started_atstring · date-time · nullableRequired
ended_atstring · date-time · nullableRequired
created_atstring · date-timeRequired
updated_atstring · date-timeRequired
local_timezonestring · max: 64Required
patch/v1/{workspace_id}/sessions/{session_id}
PATCH /v1/{workspace_id}/sessions/{session_id} HTTP/1.1
Content-Type: application/json
Accept: */*
Content-Length: 186

{
  "external_appointment_id": "text",
  "metadata": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "first_name": "text",
  "last_name": "text",
  "visit_type": "psych-intake",
  "note_template": "amd-psych-intake"
}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "status": "in-progress",
  "mode": "in_person",
  "external_appointment_id": "text",
  "first_name": "text",
  "last_name": "text",
  "visit_type": "text",
  "note_template": "amd-psych-intake",
  "started_at": "2026-01-01T00:00:00.000Z",
  "ended_at": "2026-01-01T00:00:00.000Z",
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-01-01T00:00:00.000Z",
  "local_timezone": "text",
  "artifacts": {
    "transcript": "pending",
    "note": "pending",
    "summary": "pending",
    "codes": "pending"
  }
}

Only fields present in the request body are written. Omission preserves a field; an accepted explicit null clears the corresponding nullable value. Mode remains fixed.

Use the operation above for accepted fields and constraints.

Returns the full refreshed session response. Changes to visit_type or note_template revalidate the supported pair. Changing the visit type also refreshes its checklist; that change is rejected for a terminal session.

Create Session Idempotency

When external_id is supplied on create, it acts as a per-attempt idempotency key:

  • Matching fingerprint: A repeated external_id with the same effective create parameters returns the existing session. Use the same request when retrying an ambiguous result.

  • Divergent fingerprint: If the effective create parameters differ from the stored session, the endpoint returns 409 with error code idempotency_key_conflict. Generate a new external_id for a deliberately new session.

Omitting external_id or sending null does not supply an idempotency key. Creation remains subject to permissions, validation, and the active-Zoom-session guard.

Conflict Error Codes

Session lifecycle and create endpoints return 409 responses with a stable machine-readable code in the error envelope:

Code
Trigger

idempotency_key_conflict

Create reused an external_id with a different request fingerprint.

active_zoom_session_exists

A second non-terminal Zoom session was attempted for the same practitioner.

session_streaming

End was called while a streaming worker is still attached.

invalid_session_state

The session is not in a state that permits the requested transition.

conflict

Create used an external_id that another provider's session already holds.

Zoom

Zoom Session Lifecycle

The Scribe API manages the full Zoom capture lifecycle server-side. The browser provides a meeting link and disclosure preferences; it never handles Zoom access tokens or communicates with internal capture services.

Create a Zoom Session

Supply a canonical visit_type that resolves to a supported note template, and the provider's IANA timezone. If note_template is supplied, it must match that visit type. Missing or unsupported selections fail before a session is created, even though visit_type is optional in the generated request model. Template variants and local_timezone follow the rules in Create an In-Person Session.

Create Zoom Session

post

Run the whole Zoom capture saga server-side and return {session, bot_id} (201).

In order: validate the meeting link; friendly per-practitioner active-Zoom pre-check; resolve + decrypt the STORED Zoom token (409 zoom_not_connected if absent); create the session (born in-progress, mode=zoom, external_id idempotency); dispatch the bot via the control plane with the resolved token. On dispatch failure the session is CANCELLED and any straggler bot reaped (503 bot_dispatch_failed) so nothing is orphaned. A duplicate/idempotent create whose bot is already running recovers that bot instead of dispatching a second one.

Path parameters
workspace_idstring · uuidRequired
Body

Body of POST /zoom/sessions — the whole Zoom capture saga behind one call.

The browser hands only a meeting_link + disclosure choice (never a zoomAccessToken): the Scribe API creates the session, resolves the provider's STORED Zoom token, and dispatches the bot server-side. external_id is the per-attempt idempotency key (same semantics as CreateSessionRequest).

meeting_linkstring · uri · min: 1 · max: 2083Required
external_appointment_idstring · max: 512 · nullableOptional
external_idstring · max: 512 · nullableOptional
first_namestring · max: 256 · nullableOptional
last_namestring · max: 256 · nullableOptional
visit_typestring · enum · nullableOptionalPossible values:
note_templatestring · enum · nullableOptionalPossible values:
timezonestring · enum · min: 1RequiredPossible values:
Responses
201

Successful Response

application/json

Response of POST /zoom/sessions: the created (mode=zoom, in-progress) session plus the id of the dispatched control-plane bot the live stream is bound to.

bot_idstring · max: 256Required
post/v1/{workspace_id}/zoom/sessions
POST /v1/{workspace_id}/zoom/sessions HTTP/1.1
Content-Type: application/json
Accept: */*
Content-Length: 321

{
  "meeting_link": "https://example.com",
  "disclosure": {
    "enabled": true,
    "audio_key": "text"
  },
  "external_appointment_id": "text",
  "external_id": "text",
  "metadata": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "first_name": "text",
  "last_name": "text",
  "visit_type": "psych-intake",
  "note_template": "amd-psych-intake",
  "timezone": "Africa/Abidjan"
}
{
  "session": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "status": "in-progress",
    "mode": "in_person",
    "external_appointment_id": "text",
    "first_name": "text",
    "last_name": "text",
    "visit_type": "text",
    "note_template": "amd-psych-intake",
    "started_at": "2026-01-01T00:00:00.000Z",
    "ended_at": "2026-01-01T00:00:00.000Z",
    "created_at": "2026-01-01T00:00:00.000Z",
    "updated_at": "2026-01-01T00:00:00.000Z",
    "local_timezone": "text",
    "artifacts": {
      "transcript": "pending",
      "note": "pending",
      "summary": "pending",
      "codes": "pending"
    }
  },
  "bot_id": "text"
}

Creates a Zoom capture session in one call. The server validates the meeting link, confirms the provider has a connected Zoom account, creates the session, and dispatches the capture bot.

Error responses:

Status
Code
Description

422

validation_error

The meeting link is not a Zoom URL, or another field failed validation.

422

note_template_required, unsupported_note_template

Visit type and template rules from Create an In-Person Session.

409

active_zoom_session_exists

The provider already has an active Zoom session.

409

idempotency_key_conflict

The external_id was reused with different parameters.

409

zoom_not_connected

The provider has not connected Zoom.

409

zoom_reconnect_required

Zoom rejected the stored connection; the provider must reconnect Zoom.

409

zoom_meeting_not_started

The meeting has not started. The session was cancelled; start the meeting, then create a new session.

503

zoom_refresh_unavailable

Refreshing the Zoom connection is temporarily unavailable. Retry.

503

bot_dispatch_failed

Bot dispatch failed; the session was automatically cancelled. Retryable.

Pause Zoom Bot

Pause Zoom Bot

post

Pause the Zoom capture bot bound to an owned session (proxies the control plane).

Path parameters
workspace_idstring · uuidRequired
session_idstring · uuidRequired
Responses
200

Successful Response

application/json

Response of POST /sessions/{id}/zoom/pause|resume: the bot's status after the proxied control-plane command. The live status transition also arrives over the event stream (phase 06); this is the synchronous ack.

bot_statusstring · max: 64Required
post/v1/{workspace_id}/sessions/{session_id}/zoom/pause
POST /v1/{workspace_id}/sessions/{session_id}/zoom/pause HTTP/1.1
Accept: */*
{
  "bot_status": "text"
}

Pauses the capture bot bound to the session.

Error responses:

Status
Code
Description

409

bot_not_active

No live bot is bound to this session.

502

bot_command_failed

The command could not be delivered.

Resume Zoom Bot

Resume Zoom Bot

post

Resume the Zoom capture bot bound to an owned session (proxies the control plane).

Path parameters
workspace_idstring · uuidRequired
session_idstring · uuidRequired
Responses
200

Successful Response

application/json

Response of POST /sessions/{id}/zoom/pause|resume: the bot's status after the proxied control-plane command. The live status transition also arrives over the event stream (phase 06); this is the synchronous ack.

bot_statusstring · max: 64Required
post/v1/{workspace_id}/sessions/{session_id}/zoom/resume
POST /v1/{workspace_id}/sessions/{session_id}/zoom/resume HTTP/1.1
Accept: */*
{
  "bot_status": "text"
}

Resumes a paused capture bot. Same response and error contract as pause.

End Zoom Session

End Zoom Session

delete

End a Zoom session: 202 immediately, then drain the bot + internally finalize in the background.

Returns {status: "draining"} right away; the background task stops the bot and runs the internal zoom-finalize (promote the drained snapshot -> transcript.json, flip -> in-review) with a bounded retry over the drain window. Idempotent: a second DELETE still 202s and no-ops (the drain task sees the already-finalized session and skips promotion). 409 not_zoom_session for a mic session.

Path parameters
workspace_idstring · uuidRequired
session_idstring · uuidRequired
Responses
202

Successful Response

application/json

Response of DELETE /sessions/{id}/zoom: acknowledges that the drain + internal zoom-finalize is underway. The session flips to in-review asynchronously (reaper backstop).

statusconst: drainingRequired
delete/v1/{workspace_id}/sessions/{session_id}/zoom
DELETE /v1/{workspace_id}/sessions/{session_id}/zoom HTTP/1.1
Accept: */*
{
  "status": "text"
}

Ends a Zoom session. Returns immediately; the platform stops the bot and finalizes the transcript in the background. Inspect the session and artifact state for the eventual result; the 202 acknowledgement does not establish that finalization has completed.

Idempotent - a second delete returns 202 and is a no-op.

Error responses:

Status
Code
Description

409

not_zoom_session

The session is not a Zoom session.

Zoom Connection

Providers can connect their Zoom account through the Scribe API. The platform manages the OAuth lifecycle server-side - the browser initiates the flow and reads connection status, but never handles token material.

Endpoints

Start Zoom Oauth

post

Begin the Zoom connect flow: mint a single-use server-held state + PKCE verifier bound to the provider/workspace and return the short-lived Zoom authorize URL the browser navigates to.

web_origin is the initiating web app's origin; if the code-level origin rule accepts it, it is threaded through the state so the callback can 302 the browser back to it (phase 55). A missing or rejected origin is dropped and the callback falls back to the configured return URL.

Path parameters
workspace_idstring · uuidRequired
Query parameters
web_originstring · max: 2048OptionalDefault: ""
Responses
200

Successful Response

application/json

Response of POST /zoom/oauth/authorize.

The browser navigates the top-level window to authorize_url (it cannot carry the in-memory Bearer header on a redirect, so the single-use server-held state embedded in the URL is the credential the unauthenticated callback trusts). expires_at is when that state's short TTL lapses.

authorize_urlstring · max: 2048Required
expires_atstring · date-timeRequired
post/v1/{workspace_id}/zoom/oauth/authorize
POST /v1/{workspace_id}/zoom/oauth/authorize HTTP/1.1
Accept: */*
{
  "authorize_url": "text",
  "expires_at": "2026-01-01T00:00:00.000Z"
}

Complete Zoom Oauth

get

Unauthenticated Zoom redirect target (NO Bearer -- the single-use state is the credential).

Validates + atomically consumes (GETDEL) the state, exchanges the code + PKCE verifier, and stores the encrypted tokens. Every failure -- invalid/expired/replayed state, missing code, failed exchange -- 302s to the web settings route with an error flag and renders no JSON to the human. Opted out of the provider-JWT dependency simply by omitting claims: ScribeClaimsParam.

Path parameters
workspace_idstring · uuidRequired
Query parameters
codestring · max: 2048OptionalDefault: ""
statestring · max: 512OptionalDefault: ""
Responses
302

Redirect to the web settings route with a zoom_connected=true flag on success or a zoom_error=<reason> flag on an invalid/expired/replayed state or a failed exchange.

No content

get/v1/{workspace_id}/zoom/oauth/callback
GET /v1/{workspace_id}/zoom/oauth/callback HTTP/1.1
Accept: */*

No content

Get Zoom Connection

get

Whether the calling provider has a Zoom connection. NEVER returns token material.

Heals a near-expiry token on the poll (phase 35) so a connected-but-idle workspace never lets its Zoom token lapse — the refresh + persist happen server-side before the status read, which then reflects the outcome (reconnect_required is set when Zoom has rejected the stored credential).

Path parameters
workspace_idstring · uuidRequired
Responses
200

Successful Response

application/json

Response of GET /zoom/connection. NEVER carries token material.

Deliberately holds only a boolean plus non-sensitive display fields; the encrypted access/refresh tokens live only in scribe.zoom_connections and are resolved server-side (phase 05) to dispatch a bot, never returned to a browser.

reconnect_required is true when Zoom rejected the stored refresh token (revoked/ expired), so the poll heals into a terminal state the UX can act on: the provider is still connected on record, but must re-run the OAuth connect before a Zoom start will succeed.

connectedbooleanRequired
zoom_emailstring · max: 320 · nullableOptional
connected_atstring · date-time · nullableOptional
reconnect_requiredbooleanOptionalDefault: false
get/v1/{workspace_id}/zoom/connection
GET /v1/{workspace_id}/zoom/connection HTTP/1.1
Accept: */*
{
  "connected": true,
  "zoom_email": "text",
  "connected_at": "2026-01-01T00:00:00.000Z",
  "reconnect_required": false
}

Delete Zoom Connection

delete

Disconnect Zoom: best-effort revoke at Zoom, delete the row. Idempotent -- deleting a non-existent connection still returns 204.

Path parameters
workspace_idstring · uuidRequired
Responses
204

Successful Response

No content

delete/v1/{workspace_id}/zoom/connection
DELETE /v1/{workspace_id}/zoom/connection HTTP/1.1
Accept: */*

No content

The callback is the authorization redirect target and should not be called directly.

Authorize Response

Navigate to the authorization URL returned by the Zoom authorize operation while it remains valid. The browser follows the consent flow; it does not handle provider token material.

Connection Response

Read the Zoom connection operation to confirm the provider connection before creating a capture session. A connected account does not establish that a particular meeting is ready to capture.

Error Handling

Status
Condition

401

Missing or invalid bearer token.

403

Insufficient scope or provider mismatch.

503

Zoom connect is temporarily unavailable (the authorize endpoint could not mint a verifiable state). Retry after a brief delay.

The callback endpoint never returns JSON. Every outcome - success or failure - results in a 302 redirect to the configured web settings page with a zoom_connected=true or zoom_error=<reason> query parameter.

Last updated

Was this helpful?