{"openapi":"3.1.0","info":{"title":"Voice API","version":"0.1.0","description":"Live voice quoting (`docs/voice-quoting.md`): a rep's conversation with a customer, transcribed as it happens from the browser's microphone (a telephony provider later), with each final utterance published live for the platform agent to act on. Sessions start after a consent notice, end with the minutes they transcribed (what the voice quoting add-on is metered by), and leave their transcript on the quote they built, kept by fulfillment — never what was said as a fact."},"paths":{"/sessions":{"post":{"tags":["sessions"],"operationId":"sessions.start","parameters":[],"security":[{"bearer":[]}],"responses":{"201":{"description":"VoiceSession","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionEncoded"},"examples":{"contract":{"summary":"sessions.start","value":{"id":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","status":"listening","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","source":{"kind":"browser","channels":1},"consent":{"notice":"2026-10-28","accepted":true},"startedBy":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20","startedAt":"2026-10-28T03:10:00.000Z"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"VoiceAddOnRequired | SubscriptionRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/VoiceAddOnRequiredEncoded"},{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}]}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"VoiceQuoteNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceQuoteNotFoundEncoded"}}}},"409":{"description":"VoiceQuoteNotDraft | VoiceSessionConflict | MirroredFromSource","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/VoiceQuoteNotDraftEncoded"},{"$ref":"#/components/schemas/VoiceSessionConflictEncoded"},{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}]}}}},"502":{"description":"VoiceQuoteUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceQuoteUnavailableEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Start a voice session: the conversation a rep is having with a customer, transcribed live from the audio the admin streams to `GET /sessions/:sessionId/audio`. Name the draft quote it is about with `orderId` (it must be one: 404 `VoiceQuoteNotFound`, 409 `VoiceQuoteNotDraft` for an issued quote or an order, 502 `VoiceQuoteUnavailable` when fulfillment cannot be asked), or leave it out for a conversation before there is a quote. A session starts only after the rep has told everyone on the conversation that it is transcribed and they agreed: `consent` names the version of the notice the admin showed (`notice`) and says it was `accepted`. The organization needs the voice quoting add-on: 402 `VoiceAddOnRequired` without it. Appends `voice.session-started`. Keyed on `sessionId`, the caller-minted `vcs_` id: a retry answers the session as it stands and appends nothing; the same id for another quote is 409 `VoiceSessionConflict`.\n\nRequires `orders:write`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartVoiceSessionEncoded"},"example":{"sessionId":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","consent":{"notice":"2026-10-28","accepted":true}}}},"required":true},"x-mcp-withheld":"A voice session listens to the rep's microphone on the quote page, once the rep has shown the customer the consent notice; an agent cannot hold a microphone, and hears a conversation as `voice.utterance-heard` on the tenant's stream.","x-required-scopes":["orders:write"],"x-example-source":{"origin":"contract"}},"get":{"tags":["sessions"],"operationId":"sessions.list","parameters":[{"name":"orderId","in":"query","schema":{"$ref":"#/components/schemas/OrdId"},"required":false,"example":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44"},{"name":"limit","in":"query","schema":{"type":"string"},"required":false}],"security":[{"bearer":[]}],"responses":{"200":{"description":"VoiceSessionList","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionListEncoded"},"examples":{"contract":{"summary":"sessions.list","value":{"items":[{"id":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","status":"ended","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","source":{"kind":"browser","channels":1},"consent":{"notice":"2026-10-28","accepted":true},"startedBy":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20","startedAt":"2026-10-28T03:10:00.000Z","endedAt":"2026-10-28T03:16:41.000Z","endReason":"stopped","audioSeconds":371,"billableMinutes":7,"utterances":42,"transcript":{"utterances":42,"bytes":4180,"savedAt":"2026-10-28T03:16:42.000Z"}}],"available":true}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Voice sessions, newest first (`orderId`: one quote's; `limit`: default 50, at most 200), with when each ran, its minutes and transcript, and `available`: whether the add-on lets one start. Appends nothing: a read.\n\nRequires `orders:read`.","x-mcp-tool":{"name":"voice_list_sessions","title":"Voice: Voice sessions","toolset":"voice","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"x-required-scopes":["orders:read"],"x-example-source":{"origin":"contract"}}},"/sessions/{sessionId}":{"get":{"tags":["sessions"],"operationId":"sessions.get","parameters":[{"name":"sessionId","in":"path","schema":{"$ref":"#/components/schemas/VcsId"},"required":true,"example":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"VoiceSession","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionEncoded"},"examples":{"contract":{"summary":"sessions.get","value":{"id":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","status":"ended","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","source":{"kind":"browser","channels":1},"consent":{"notice":"2026-10-28","accepted":true},"startedBy":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20","startedAt":"2026-10-28T03:10:00.000Z","endedAt":"2026-10-28T03:16:41.000Z","endReason":"stopped","audioSeconds":371,"billableMinutes":7,"utterances":42,"transcript":{"utterances":42,"bytes":4180,"savedAt":"2026-10-28T03:16:42.000Z"}}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"VoiceSessionNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionNotFoundEncoded"}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"One voice session: its quote, consent, start, end and why, minutes transcribed and saved transcript. 404 `VoiceSessionNotFound`. Appends nothing: a read.\n\nRequires `orders:read`.","x-mcp-withheld":"One session by id, for the admin's quote page; voice_list_sessions answers each session whole, narrowed to a quote by `orderId`.","x-required-scopes":["orders:read"],"x-example-source":{"origin":"contract"}}},"/sessions/{sessionId}/quote":{"post":{"tags":["sessions"],"operationId":"sessions.linkQuote","parameters":[{"name":"sessionId","in":"path","schema":{"$ref":"#/components/schemas/VcsId"},"required":true,"example":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"VoiceSession","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionEncoded"},"examples":{"contract":{"summary":"sessions.linkQuote","value":{"id":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","status":"listening","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","source":{"kind":"browser","channels":1},"consent":{"notice":"2026-10-28","accepted":true},"startedBy":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20","startedAt":"2026-10-28T03:10:00.000Z"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"VoiceSessionNotFound | VoiceQuoteNotMade","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/VoiceSessionNotFoundEncoded"},{"$ref":"#/components/schemas/VoiceQuoteNotMadeEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"502":{"description":"VoiceQuoteUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceQuoteUnavailableEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Link a session started before there was a quote to the draft quote the conversation made: the order whose `reference` is the session's `vcs_` id — the platform agent creates the draft with it as its key — read from fulfillment with the rep's own bearer. From then the session's utterances name that quote and its transcript is kept on it. 404 `VoiceSessionNotFound`; 404 `VoiceQuoteNotMade` while no order carries the session's id yet; 502 `VoiceQuoteUnavailable` when fulfillment cannot be asked. Appends `voice.session-linked`. Idempotent by state: a session is linked once, so linking one already on a quote (started on it, or linked before) answers it as it is and appends nothing.\n\nRequires `orders:write`.","x-mcp-withheld":"The rep's screen links its live conversation to the draft quote the agent made from it (keyed by the session's id), then moves to that draft; nothing an agent decides.","x-required-scopes":["orders:write"],"x-example-source":{"origin":"contract"}}},"/sessions/{sessionId}/end":{"post":{"tags":["sessions"],"operationId":"sessions.end","parameters":[{"name":"sessionId","in":"path","schema":{"$ref":"#/components/schemas/VcsId"},"required":true,"example":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"VoiceSession","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionEncoded"},"examples":{"contract":{"summary":"sessions.end","value":{"id":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","status":"ended","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","source":{"kind":"browser","channels":1},"consent":{"notice":"2026-10-28","accepted":true},"startedBy":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20","startedAt":"2026-10-28T03:10:00.000Z","endedAt":"2026-10-28T03:16:41.000Z","endReason":"stopped","audioSeconds":371,"billableMinutes":7,"utterances":42,"transcript":{"utterances":42,"bytes":4180,"savedAt":"2026-10-28T03:16:42.000Z"}}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"VoiceSessionNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSessionNotFoundEncoded"}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Stop listening: the audio connection, if one is open, is closed, and the session ends with the audio it transcribed — whole minutes, rounded up, are what the add-on is metered by. Appends `voice.session-ended` (reason `stopped`), then — for a session on a quote — hands the transcript to fulfillment, which keeps it on the order (`fulfillment.transcript-attached`, read through `POST /orders/:orderId/transcripts/:sessionId/link`), and appends `voice.transcript-saved` naming it; a session that made no quote keeps no transcript. A session nobody stops is ended the same way by the service's sweep, two minutes after its audio stopped arriving (reason `disconnected`). 404 `VoiceSessionNotFound`. Idempotent by state: a session ends once, and ending an ended one answers it as it is and appends nothing.\n\nRequires `orders:write`.","x-mcp-withheld":"Stopping a conversation the rep is having is the rep's control on the quote page; a session nobody stops is ended by the service's sweep once its audio has gone.","x-required-scopes":["orders:write"],"x-example-source":{"origin":"contract"}}},"/sessions/{sessionId}/audio":{"get":{"tags":["sessions"],"operationId":"sessions.audio","parameters":[{"name":"sessionId","in":"path","schema":{"$ref":"#/components/schemas/VcsId"},"required":true,"example":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33"}],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"string"},"examples":{"contract":{"summary":"Upgrade, send the auth frame, stream audio; the server answers frames like this one.","value":"{\"type\":\"transcript\",\"kind\":\"final\",\"utteranceId\":\"u-3\",\"text\":\"Twelve of the blue widgets, please.\",\"speaker\":1,\"atMs\":8420}"}}}}}},"description":"WebSocket upgrade: the session's audio in, its transcript out. Browsers cannot set headers on an upgrade, so the FIRST frame must be `{\"type\":\"auth\",\"token\":\"<jwt>\"}` within ten seconds — the token of the person who started the session, in its organization, holding `orders:write` — or the server answers an `error` frame and closes. Then binary frames are audio (the browser's `MediaRecorder` chunks), and text frames `pause` and `resume` control it (paused audio is neither transcribed nor billed) while `token` hands over a renewed JWT. The server sends `ready`, `state`, and a `transcript` frame per interim guess and per `final` utterance; each final is also published live on the organization's stream (the events gateway's `voice:session:<sessionId>` room). A connection that drops can be opened again and the session carries on where it was. Appends nothing: the socket only listens — stopping is `POST /sessions/:sessionId/end`, and a session nobody stops is ended by the service's sweep once its audio has been gone two minutes. A plain GET without an upgrade returns 426.\n\nPublic: the socket authenticates its first frame with the rep's JWT and holds it to the session's tenant and person","x-mcp-withheld":"The WebSocket the admin streams the microphone's audio into, not a request and response a tool call can make; what was said reaches an agent as `voice.utterance-heard` and the transcript kept on the quote (fulfillment_link_transcript).","x-requires":{"kind":"public","reason":"the socket authenticates its first frame with the rep's JWT and holds it to the session's tenant and person"},"x-example-source":{"origin":"contract"}}},"/events":{"get":{"tags":["events"],"operationId":"events.list","parameters":[{"name":"since","in":"query","schema":{"type":"string"},"required":false,"example":"7"},{"name":"limit","in":"query","schema":{"type":"string"},"required":false,"example":"500"},{"name":"upTo","in":"query","schema":{"type":"string"},"required":false}],"security":[{"bearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/voice.session-startedEncoded"},{"$ref":"#/components/schemas/voice.session-linkedEncoded"},{"$ref":"#/components/schemas/voice.session-endedEncoded"},{"$ref":"#/components/schemas/voice.transcript-savedEncoded"}]}},"examples":{"contract":{"summary":"events.list","value":[{"_tag":"voice.session-started","eventId":"evt_01a15a34-5b21-7c90-8e3f-1a2b3c4d5e66","txId":"tx_01a15a35-6c32-7da1-9f40-2b3c4d5e6f77","tenantId":"org_01a15a30-55c2-7c4e-9b1d-3f2a8e6c0d11","sequence":7,"occurredAt":"2026-10-28T03:10:00.000Z","source":"voice-manager","version":1,"actor":{"_tag":"user","id":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20"},"correlationId":"req_01a15a36-7d43-7eb2-a051-3c4d5e6f7a88","payload":{"sessionId":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","orderId":"ord_01a15a33-19a4-7b5d-b0e1-2c7f6a8d9e44","source":{"kind":"browser","channels":1},"consent":{"notice":"2026-10-28","accepted":true}}},{"_tag":"voice.session-ended","eventId":"evt_01a15a37-8e54-7fc3-b162-4d5e6f7a8b99","txId":"tx_01a15a38-9f65-70d4-8273-5e6f7a8b9caa","tenantId":"org_01a15a30-55c2-7c4e-9b1d-3f2a8e6c0d11","sequence":8,"occurredAt":"2026-10-28T03:16:41.000Z","source":"voice-manager","version":1,"actor":{"_tag":"user","id":"usr_01a15a31-0b7e-7a12-8d44-6c5e2b9f1a20"},"correlationId":"req_01a15a39-a076-71e5-9384-6f7a8b9cadbb","payload":{"sessionId":"vcs_01a15a32-7d10-7f3b-a2c6-4e8b1d0f5c33","reason":"stopped","audioSeconds":371,"billableMinutes":7,"utterances":42}}]}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Replay committed voice events at-or-after `since` (a journal sequence number), oldest first: every session started, linked to the quote it made, ended with its transcribed minutes, and its transcript handed to the quote. What was said is never a fact. One response is a page: `limit` defaults to 500 and is capped at 5000 (an over-cap request is clamped). Pages are `sequence`-ordered and the boundary is stable — repeat with `since=<last event's sequence + 1>` until a page comes back smaller than `limit` to replay the journal exactly once. `upTo` (inclusive) ends the replay at a sequence instead of the journal's head — with `GET /events/head` it replays the journal as it stood at a moment. Appends nothing: a read of facts already journalled.\n\nRequires `orders:read` or `activity:read`.","x-mcp-withheld":"The journal replay a consumer pages through to build its projection; agents read the projections the list and get tools serve, and the audit trail (`audit_trail`) for history.","x-required-scopes":["orders:read","activity:read"],"x-example-source":{"origin":"contract"}}},"/events/head":{"get":{"tags":["events"],"operationId":"events.head","parameters":[{"name":"at","in":"query","schema":{"type":"string"},"required":true,"example":"2026-10-28T04:00:00.000Z"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"Where a tenant's journal stood at a moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalHead"},"examples":{"contract":{"summary":"events.head","value":{"at":"2026-10-28T04:00:00.000Z","sequence":9}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"The journal's position at a moment: the last `sequence` the database had recorded for this tenant at `at` (absent when it held nothing yet), by the database's own clock rather than the service's. Replaying with `upTo=<sequence>` then gives the journal exactly as it stood then; a set of heads taken at one `at` is a consistent cut across journals. Appends nothing: a read of facts already journalled.\n\nRequires `orders:read` or `activity:read`.","x-mcp-withheld":"Where a journal stood at a moment, for a consumer cutting journals to replay them as of then; agents read history through the audit trail (`audit_trail`).","x-required-scopes":["orders:read","activity:read"],"x-example-source":{"origin":"contract"}}}},"components":{"schemas":{"VcsId":{"type":"string","pattern":"^vcs_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A vcs-prefixed uuid, e.g. vcs_9f8c1c2e-0000-4000-8000-000000000000"},"OrdId":{"type":"string","pattern":"^ord_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A ord-prefixed uuid, e.g. ord_9f8c1c2e-0000-4000-8000-000000000000"},"VoiceConsent":{"type":"object","properties":{"notice":{"type":"string","minLength":1,"maxLength":64},"accepted":{"type":"boolean","enum":[true]}},"required":["notice","accepted"],"additionalProperties":false,"description":"The consent notice shown before listening began, and that it was accepted."},"StartVoiceSessionEncoded":{"type":"object","properties":{"sessionId":{"$ref":"#/components/schemas/VcsId"},"orderId":{"$ref":"#/components/schemas/OrdId"},"consent":{"$ref":"#/components/schemas/VoiceConsent"}},"required":["sessionId","consent"],"additionalProperties":false},"VoiceSessionStatus":{"type":"string","enum":["listening","ended"],"description":"Where a voice session stands: `listening` until it ends, then `ended`."},"VoiceAudioSource":{"type":"object","properties":{"kind":{"type":"string","enum":["browser"]},"channels":{"type":"integer","exclusiveMinimum":0}},"required":["kind","channels"],"additionalProperties":false,"description":"Where a voice session's audio comes from: the browser's microphone (one channel)."},"VoiceSessionEndReason":{"type":"string","enum":["stopped","disconnected"],"description":"Why a voice session ended: `stopped` by the rep, or `disconnected` — its audio stopped arriving and nobody stopped it, so it was ended two minutes later at the last audio heard."},"VoiceTranscriptInfo":{"type":"object","properties":{"utterances":{"type":"integer","minimum":0},"bytes":{"type":"integer","minimum":0},"savedAt":{"type":"string"}},"required":["utterances","bytes","savedAt"],"additionalProperties":false,"description":"A voice session's transcript, kept on its quote by fulfillment: its utterances and size."},"VoiceSessionEncoded":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/VcsId"},"status":{"$ref":"#/components/schemas/VoiceSessionStatus"},"orderId":{"$ref":"#/components/schemas/OrdId"},"source":{"$ref":"#/components/schemas/VoiceAudioSource"},"consent":{"$ref":"#/components/schemas/VoiceConsent"},"startedBy":{"type":"string"},"startedAt":{"type":"string"},"endedAt":{"type":"string"},"endReason":{"$ref":"#/components/schemas/VoiceSessionEndReason"},"audioSeconds":{"type":"integer","minimum":0},"billableMinutes":{"type":"integer","minimum":0},"utterances":{"type":"integer","minimum":0},"transcript":{"$ref":"#/components/schemas/VoiceTranscriptInfo"}},"required":["id","status","source","consent","startedBy","startedAt"],"additionalProperties":false},"VoiceAddOnRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceAddOnRequired"]},"reason":{"type":"string"}},"required":["_tag","reason"],"additionalProperties":false},"SubscriptionRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["SubscriptionRequired"]},"status":{"type":"string"}},"required":["_tag","status"],"additionalProperties":false},"VoiceQuoteNotFoundEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceQuoteNotFound"]},"orderId":{"type":"string"}},"required":["_tag","orderId"],"additionalProperties":false},"VoiceQuoteNotDraftEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceQuoteNotDraft"]},"orderId":{"type":"string"},"status":{"type":"string"}},"required":["_tag","orderId","status"],"additionalProperties":false},"VoiceSessionConflictEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceSessionConflict"]},"sessionId":{"type":"string"},"reason":{"type":"string"}},"required":["_tag","sessionId","reason"],"additionalProperties":false},"MirroredFromSourceEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["MirroredFromSource"]},"source":{"type":"string"}},"required":["_tag","source"],"additionalProperties":false},"VoiceQuoteUnavailableEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceQuoteUnavailable"]},"reason":{"type":"string"}},"required":["_tag","reason"],"additionalProperties":false},"UnauthorizedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["Unauthorized"]},"reason":{"type":"string"}},"required":["_tag","reason"],"additionalProperties":false},"TokenAlreadyUsedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["TokenAlreadyUsed"]},"tokenId":{"type":"string"}},"required":["_tag","tokenId"],"additionalProperties":false},"RequestLogUnavailableEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["RequestLogUnavailable"]},"tokenId":{"type":"string"},"reason":{"type":"string"}},"required":["_tag","tokenId","reason"],"additionalProperties":false},"TenantRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["TenantRequired"]},"userId":{"type":"string"}},"required":["_tag","userId"],"additionalProperties":false},"ScopeRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["ScopeRequired"]},"required":{"type":"array","items":{"type":"string"}}},"required":["_tag","required"],"additionalProperties":false},"PlatformAdminRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["PlatformAdminRequired"]},"userId":{"type":"string"}},"required":["_tag","userId"],"additionalProperties":false},"VoiceSessionListEncoded":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/VoiceSessionEncoded"}},"available":{"type":"boolean"}},"required":["items","available"],"additionalProperties":false},"VoiceSessionNotFoundEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceSessionNotFound"]},"sessionId":{"type":"string"}},"required":["_tag","sessionId"],"additionalProperties":false},"VoiceQuoteNotMadeEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["VoiceQuoteNotMade"]},"sessionId":{"type":"string"}},"required":["_tag","sessionId"],"additionalProperties":false},"EvtId":{"type":"string","pattern":"^evt_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A evt-prefixed uuid, e.g. evt_9f8c1c2e-0000-4000-8000-000000000000"},"TxId":{"type":"string","pattern":"^tx_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A tx-prefixed uuid, e.g. tx_9f8c1c2e-0000-4000-8000-000000000000"},"TenantId":{"type":"string","pattern":"^org_(test_)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"An org-prefixed uuid, e.g. org_9f8c1c2e-0000-4000-8000-000000000000; a sandbox tenant is org_test_<uuid>"},"UsrId":{"type":"string","pattern":"^usr_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A usr-prefixed uuid, e.g. usr_9f8c1c2e-0000-4000-8000-000000000000"},"AppId":{"type":"string","pattern":"^app_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A app-prefixed uuid, e.g. app_9f8c1c2e-0000-4000-8000-000000000000"},"InsId":{"type":"string","pattern":"^ins_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A ins-prefixed uuid, e.g. ins_9f8c1c2e-0000-4000-8000-000000000000"},"CplId":{"type":"string","pattern":"^cpl_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A cpl-prefixed uuid, e.g. cpl_9f8c1c2e-0000-4000-8000-000000000000"},"Actor":{"anyOf":[{"type":"object","properties":{"_tag":{"type":"string","enum":["user"]},"id":{"$ref":"#/components/schemas/UsrId"},"impersonatedBy":{"type":"string","minLength":1},"viaPartner":{"type":"string","minLength":1}},"required":["_tag","id"],"additionalProperties":false},{"type":"object","properties":{"_tag":{"type":"string","enum":["system"]},"id":{"type":"string","minLength":1}},"required":["_tag","id"],"additionalProperties":false},{"type":"object","properties":{"_tag":{"type":"string","enum":["app"]},"id":{"$ref":"#/components/schemas/AppId"},"installationId":{"$ref":"#/components/schemas/InsId"}},"required":["_tag","id","installationId"],"additionalProperties":false},{"type":"object","properties":{"_tag":{"type":"string","enum":["customer"]},"id":{"$ref":"#/components/schemas/CplId"}},"required":["_tag","id"],"additionalProperties":false}]},"voice.session-startedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["voice.session-started"]},"eventId":{"$ref":"#/components/schemas/EvtId"},"txId":{"$ref":"#/components/schemas/TxId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"sequence":{"type":"integer","minimum":0},"occurredAt":{"type":"string"},"source":{"type":"string","minLength":1},"version":{"type":"number","enum":[1]},"actor":{"$ref":"#/components/schemas/Actor"},"correlationId":{"type":"string","minLength":1},"causationId":{"type":"string","minLength":1},"payload":{"type":"object","properties":{"sessionId":{"$ref":"#/components/schemas/VcsId"},"orderId":{"$ref":"#/components/schemas/OrdId"},"source":{"$ref":"#/components/schemas/VoiceAudioSource"},"consent":{"$ref":"#/components/schemas/VoiceConsent"}},"required":["sessionId","source","consent"],"additionalProperties":false}},"required":["_tag","eventId","txId","tenantId","sequence","occurredAt","source","version","actor","correlationId","payload"],"additionalProperties":false},"voice.session-linkedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["voice.session-linked"]},"eventId":{"$ref":"#/components/schemas/EvtId"},"txId":{"$ref":"#/components/schemas/TxId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"sequence":{"type":"integer","minimum":0},"occurredAt":{"type":"string"},"source":{"type":"string","minLength":1},"version":{"type":"number","enum":[1]},"actor":{"$ref":"#/components/schemas/Actor"},"correlationId":{"type":"string","minLength":1},"causationId":{"type":"string","minLength":1},"payload":{"type":"object","properties":{"sessionId":{"$ref":"#/components/schemas/VcsId"},"orderId":{"$ref":"#/components/schemas/OrdId"}},"required":["sessionId","orderId"],"additionalProperties":false}},"required":["_tag","eventId","txId","tenantId","sequence","occurredAt","source","version","actor","correlationId","payload"],"additionalProperties":false},"voice.session-endedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["voice.session-ended"]},"eventId":{"$ref":"#/components/schemas/EvtId"},"txId":{"$ref":"#/components/schemas/TxId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"sequence":{"type":"integer","minimum":0},"occurredAt":{"type":"string"},"source":{"type":"string","minLength":1},"version":{"type":"number","enum":[1]},"actor":{"$ref":"#/components/schemas/Actor"},"correlationId":{"type":"string","minLength":1},"causationId":{"type":"string","minLength":1},"payload":{"type":"object","properties":{"sessionId":{"$ref":"#/components/schemas/VcsId"},"reason":{"$ref":"#/components/schemas/VoiceSessionEndReason"},"audioSeconds":{"type":"integer","minimum":0},"billableMinutes":{"type":"integer","minimum":0},"utterances":{"type":"integer","minimum":0}},"required":["sessionId","reason","audioSeconds","billableMinutes","utterances"],"additionalProperties":false}},"required":["_tag","eventId","txId","tenantId","sequence","occurredAt","source","version","actor","correlationId","payload"],"additionalProperties":false},"voice.transcript-savedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["voice.transcript-saved"]},"eventId":{"$ref":"#/components/schemas/EvtId"},"txId":{"$ref":"#/components/schemas/TxId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"sequence":{"type":"integer","minimum":0},"occurredAt":{"type":"string"},"source":{"type":"string","minLength":1},"version":{"type":"number","enum":[1]},"actor":{"$ref":"#/components/schemas/Actor"},"correlationId":{"type":"string","minLength":1},"causationId":{"type":"string","minLength":1},"payload":{"type":"object","properties":{"sessionId":{"$ref":"#/components/schemas/VcsId"},"orderId":{"$ref":"#/components/schemas/OrdId"},"utterances":{"type":"integer","minimum":0},"bytes":{"type":"integer","minimum":0}},"required":["sessionId","orderId","utterances","bytes"],"additionalProperties":false}},"required":["_tag","eventId","txId","tenantId","sequence","occurredAt","source","version","actor","correlationId","payload"],"additionalProperties":false},"JournalHead":{"type":"object","properties":{"at":{"type":"string"},"sequence":{"type":"integer","minimum":0}},"required":["at"],"additionalProperties":false,"description":"Where a tenant's journal stood at a moment."}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A tenant JWT: sign in through the auth service, choose the organization, then `GET /api/auth/token`. Tokens last 15 minutes."}}},"security":[],"tags":[{"name":"sessions","description":"A rep's conversations with customers, transcribed live: started after consent, metered in minutes, kept as transcripts."},{"name":"events","description":"The voice service's append-only event log."}],"servers":[{"url":"https://voice.getmanifold.io","description":"Production"}]}