Reference

Endpoints

Every operation of the VocalStack API, each with its TypeScript SDK, Python SDK and curl sample. Base URL: https://api.vocalstack.com.

billing

  • GET /v1/billing Get the account's billing
    The acting account's plan, rates (dollars an hour of audio, and the minimum a transcription is billed: `minimumSeconds`), credit balance, whether it runs on in a grace period below zero (`inGrace`), whether a new transcription would start now and what would refuse it (`canStart`, `startBlock` for a file; `canStartLive`, `startBlockLive` for a live transcription or realtime session, whose minimum costs more), the billing period and the one before, the monthly credit's use, the counted limits in use, the subscription (next payment, a scheduled interval switch, past due), auto top-up with its last attempt, the low-balance alert, a payment still being processed, the default card, a scheduled rate change, the retention deadline after a downgrade, the plan's limits and whether it has paid. A creation that would overdraw the balance, or a new transcription when the balance does not cover its minimum, is refused 402 `insufficient_credit`; `topUpUrl` is where to add credit. `enabled: false` means this server does not bill.
  • PUT /v1/billing/auto-top-up Set auto top-up
    Turn auto top-up on (`threshold` and `amount`: any whole-cent values inside the plan list's `autoTopUp.thresholdRange` and `amountRange`; when the balance falls to the threshold, the amount is charged to the saved payment method, at most a few times a day) or off. `409 payment_method_required` until the account has a saved payment method; `409 invalid_state` while the payment provider takes no automatic charges (`autoTopUp.offered: false` on `GET /v1/billing`). The consent (time, hashed address, terms version) is recorded.
  • POST /v1/billing/auto-top-up/retry Run auto top-up now
    Charge the configured auto top-up amount to the saved payment method now, whatever the balance (after a declined attempt, once the card is fixed). Counts against the day's cap: `429 rate_limited` when it is used. `409 auto_top_up_off` when auto top-up is off; `409 invalid_state` while another charge for the account is in progress or automatic charges are not offered. Returns the auto top-up with its `last` attempt (`paid`, `declined` or `pending`).
  • GET /v1/billing/charges List the charges
    The account's per-recording charges, newest first, with the transcription's name: open while the audio runs (metered every minute), settled once the recording ends, void when waived. Page with `cursor`.
  • POST /v1/billing/checkouts Open a checkout
    Start a payment at the payment provider: `{kind: "topup", amount}` adds credit (any whole-cent amount inside the plan list's `topUpRange`), `{kind: "subscribe", planId, interval}` starts a subscription (`month` or `year`); `promoCode` adds a code's bonus credit to a top-up or its discount to a subscription's first payment (`404 promo_code_invalid` when it does not apply; a code counts against the promo check's hourly limit, `429 rate_limited`). Both need `acceptTerms: true` or the request is `422 invalid_body`: the one consent, the Terms and the customer's request that the purchase start now. `waiveWithdrawal` is deprecated and ignored. Send the customer to `url`; the provider returns them to the app's billing page with `?checkout=<id>`. A signed-in person only (for an organization, its owner or admin), never an API key. `409 invalid_state` with an active subscription (cancel it first) or a plan billed by hand. `409 invalid_state` too when the payment provider refuses the call (an address it takes no mail at, a tax ID it rejects), with its reason in `message`: retrying will not help; `503 unavailable` only when it did not answer. Idempotent with `Idempotency-Key`.
  • GET /v1/billing/checkouts/{id} Get a checkout
    A checkout's status, for the page the customer comes back to: by its `checkoutId` or the provider's id (`?checkout=` on the return URL). `succeeded` once the payment landed (the credit or the subscription is then in `GET /v1/billing`).
  • GET /v1/billing/details Get the invoice details
    The name, email, address and tax id invoices and receipts carry. `email` is the sign-in email until another is saved.
  • PUT /v1/billing/details Set the invoice details
    Save the invoice details; they are written onto the provider's customer and prefill every checkout. `country` is ISO 3166-1 alpha-2; an EU VAT ID starts with its country's prefix (Greece: `EL`) and has 8 to 12 letters or digits (spaces, dots and dashes are dropped). `422 invalid_body` names the `field`.
  • GET /v1/billing/ledger List the ledger
    The account's credit movements, newest first: signup credit, top-ups, monthly credit, charges, corrections, refunds. Page with `cursor`.
  • PUT /v1/billing/low-balance-alert Set the low-balance alert
    Turn the low-balance email on or off and set its line (`threshold`, inside the plan list's `lowBalanceAlert.range`): one email each time the balance falls to it.
  • GET /v1/billing/payment-methods List the payment methods
    The cards saved at the payment provider: brand, last 4, expiry, wallet, which is the default, and whether the last automatic charge on it was declined. Empty before the first payment or card. For an organization, its owner or admin.
  • POST /v1/billing/payment-methods/manage Add or change a payment method
    A link to the payment provider's portal, where a card is added, replaced or made the default (the provider has no API for those); it returns to the app's payment tab. Works before the first payment.
  • DELETE /v1/billing/payment-methods/{id} Remove a payment method
    Remove a saved card. `409 payment_method_in_use` while it pays for the subscription. Removing the last one turns auto top-up off.
  • GET /v1/billing/payments List the payments
    The account's payments history, newest first: top-ups, auto top-ups and subscription payments (`paid`, `pending` while the provider processes one, `failed` for a declined charge or renewal), refunds (`refunded`) and credit never paid for (`credit`: the signup credit, a promo code's bonus, an adjustment). `document` says whether an `invoice` or a `receipt` can be fetched. `businessPurchase` and `taxId`: a purchase made with a tax ID (on the invoice details or given at checkout) is a business purchase. Page with `cursor`.
  • GET /v1/billing/payments/{id}/document Get a payment's invoice or receipt
    A link to the payment's invoice (a subscription) or receipt (a top-up), valid for a short while. The provider makes it on the first ask: `202` with `{pending: true}` until then, ask again in a moment. `409 billing_details_required` when it needs a billing name and address (`PUT /v1/billing/details`). A signed-in person only (for an organization, its owner or admin), never an API key: the first ask writes the document with the invoice details as they stand.
  • GET /v1/billing/plans List the plans
    The visible plans with their current rates (with the minimum a transcription is billed), prices, included credit, whether running work goes on in a grace period when the credit runs out (`graceOnZero`), limits and features, plus the top-up presets and range, the auto top-up and low-balance alert choices and ranges, the signup credit and the downgrade grace in days. No credential needed.
  • GET /v1/billing/portal Get the customer portal link
    A link to the payment provider's customer portal (payment methods, invoices, receipts), valid for a short while. `409 payment_method_required` before the first checkout.
  • POST /v1/billing/promo-codes/check Check a promo code
    What a code gives `for` a `topup` (a bonus credit) or a `subscribe` (a discount off the first payment), before the checkout. `404 promo_code_invalid` when it does not exist, has expired, is used up, was redeemed by this account or gives nothing for this purchase. Rate-limited per account (a checkout carrying a `promoCode` counts against the same limit). For an organization, its owner or admin.
  • POST /v1/billing/subscription/cancel Cancel the subscription
    Cancel at the end of the current period: nothing changes until then; after it the account moves to the default plan and unspent monthly credit is removed. `409 invalid_state` without a subscription.
  • POST /v1/billing/subscription/interval Switch the billing interval
    From the next period the subscription renews `month`ly or `year`ly (nothing is charged now); `subscription.pendingInterval` shows the switch until it applies. `409 invalid_state` without a subscription or when it ends at the period end.
  • DELETE /v1/billing/subscription/interval Keep the billing interval
    Take back a scheduled interval switch.
  • POST /v1/billing/subscription/uncancel Keep the subscription
    Take back a cancellation scheduled for the period end.
  • GET /v1/billing/usage Get the usage report
    What the account spent per day (in `tz`), per source (`dashboard` or the API key that made the transcription, deleted recordings included) and per kind (`file`, `live`): audio seconds and dollars, with running transcriptions at their current amount. `startDate` and `endDate` are inclusive days (`YYYY-MM-DD`); a start before the account's first day is moved to it and an end after today to today (the answer's `startDate` and `endDate` say what was used); at most 92 days (`400 range_too_long`).
  • GET /v1/billing/usage/charges List the usage report's charges
    The charges behind the usage report, one by one, newest first: each file or link transcription, live recording and realtime session billed in the range (a running one at its current amount, `state: open`), with the transcription's name, its kind, its source (`dashboard` or the API key's id, as the report's `sources`), the seconds billed, the rate and the cost; money given back for a charge is a `correction` with a negative amount. `count` and `total` cover every charge matching the filters, not just the page. The range is the usage report's (`startDate`, `endDate`, `tz`: inclusive days, at most 92, `400 range_too_long`); `kind` (`file` or `live`) and `source` narrow it. Page with `cursor`.

broadcasts

  • GET /v1/broadcasts List broadcasts
    Broadcasts owned by the acting principal. `lifecycle=all` is the active and the archived in one answer (each says which it is in its `state`), up to 500 of each — what a dashboard that shows them all should ask, once.
  • POST /v1/broadcasts Create a broadcast
    Create a broadcast: the link listeners open (`code`), which a host can change later (the old one keeps working).
  • GET /v1/broadcasts/{id} Get a broadcast
    One broadcast of the acting principal's, by id.
  • PATCH /v1/broadcasts/{id} Update a broadcast
    Rename, change access/password, change the link (`code`; the links it had keep opening it), or update default capture settings.
  • POST /v1/broadcasts/{id}/archive Archive a broadcast
    Archive the broadcast: hidden, its links dead, its data kept until it is restored or purged.
  • POST /v1/broadcasts/{id}/audio-sources Add an audio source
    Give a broadcast a stream it can record from — a YouTube live, an internet radio address (`audioSources`). `broadcasts.startRecording` with `audioSource` set to its id records it: each such recording is a live transcription of its own, attached to the broadcast. Returns the broadcast.
  • DELETE /v1/broadcasts/{id}/audio-sources/{source} Remove an audio source
    Take an audio source off a broadcast. What was recorded from it stays. Returns the broadcast.
  • GET /v1/broadcasts/{id}/audio-sources/{source}/check Check an audio source
    Whether an audio source can be recorded right now: the server opens it as a recording would — a YouTube link resolved to its live stream, a radio address connected, a playlist followed, the first audio decoded — and says whether audio came back (`state`). When it did not: what went wrong (`problem`, `message`, `httpStatus`), and, when one of the likely mistakes — an extension a letter off, the other scheme, the stream a web page plays — was opened and gave audio, that address (`fix`). Nothing is recorded. A ready answer stands for a minute and a failed one for 20 s, unless `fresh` asks again.
  • POST /v1/broadcasts/{id}/purge Purge a broadcast
    Delete an archived broadcast and everything in it, for good.
  • GET /v1/broadcasts/{id}/recordings List a broadcast's recordings
    The broadcast's recordings, newest first, a page at a time: follow `nextCursor` (absent on the last page) as `cursor`. `lifecycle=archived` lists the archived ones.
  • POST /v1/broadcasts/{id}/recordings Start a recording
    Start recording on the broadcast. The recording is made in a new live transcription that hears the broadcast's microphone — or, with `audioSource`, one of its audio sources — and is attached to it: `recording.transcriptionId` names that transcription, the broadcast's link shows it (`currentRecording`), and it is listed with the transcriptions. Mints a publisher realtime session (`streamUrl`, `sessionId`); 409 conflict with details.takeover when another device is recording. `scriptText` gives the recording words to follow like a teleprompter (`Recording.scriptText`).
  • POST /v1/broadcasts/{id}/restore Restore a broadcast
    Bring an archived broadcast back.
  • GET /v1/broadcasts/{id}/share-links List a broadcast's share links
    Active share links of the broadcast.
  • POST /v1/broadcasts/{id}/share-links Create a share link
    A named link ("Who is it for?") to the read-only public page. `allowDownload`, `allowExport` and `allowTranslate` are all on by default and per link. Send `allowTranslate: false` to close a link to translation; it takes effect from the next request.

connect

  • POST /v1/connect/token Redeem a connect code
    One-click Connect ([guide](/docs/guides/connect-an-app.md)): your server swaps the `code` the dashboard sent to your `redirect_uri` for an API key, with the PKCE `code_verifier` (OAuth 2.0 authorization code + PKCE; the access token is the key). No credential. The code works once and for two minutes; a second redemption, a wrong verifier or another `redirect_uri` is `400 invalid_grant`, and the code is spent either way. A request from a web page is refused: call it from your server. Errors are OAuth's `{ error, error_description }`, never the API's error envelope, but for `429` and `503`. The answer is `Cache-Control: no-store`.

corrections

  • POST /v1/corrections/{id}/revert Revert a correction
    Undo one correction.
  • GET /v1/recordings/{id}/corrections List corrections
    The corrections made to the recording's transcript, newest first, a page at a time: follow `nextCursor` (absent on the last page) as `cursor`.
  • POST /v1/recordings/{id}/corrections Apply corrections
    Apply a batch of word edits and line rewrites atomically; every target must be settled. Each correction says whether its line is voiced as corrected (`voiced`): the voice may only say what was said, so a correction is voiced only when every word it says is a word of the recognizer's text (punctuation, case, Latin accents and number formatting aside) or of a fresh reading of the line's audio, taken automatically when the recognizer's text is not enough, and it drops no negation the audio has. A line spanning several segments lists neighbouring segments only (400 `invalid_options` otherwise). Any other correction is saved and read, but voice clips and voice tracks keep speaking what the recognizer heard (`notVoicedReason: rewrite`). VocalStack speaks transcripts, never text a caller wrote.
  • POST /v1/recordings/{id}/retranscribe Retranscribe a line
    Read one line's audio again with the language forced, and apply what the recognizer hears as a line rewrite. A line heard in the wrong language cannot be repaired word by word — every word is wrong together — so this is the repair for it. The segments must be settled, like every other correction; the answer is the same `line` corrections a hand-typed rewrite produces, with the same revert behind them. 503 `engine_unavailable` means the audio for that line has not reached this machine yet and the ask is worth repeating.

jobs

  • GET /v1/recordings/{id}/job Get a job
    The recording's transcription job: its state and progress (done/total segments, media seconds, pct). A `queued` job with `queue` is waiting its turn behind the account's other transcriptions (the plan's `concurrentTranscriptions` are running) and starts by itself when one ends; `queue.position` 1 is the next to start.
  • GET /v1/recordings/{id}/job/preview Get a job's preview media
    A job waiting in `cropping`: the media for the trim step to draw the waveform from in the browser. From a link (`preview: true`), the file the server fetched — read once, kept until the job is started or for ten minutes, never stored; from an upload, its stored source streamed through. 404 once a link's copy is gone.
  • POST /v1/recordings/{id}/job/retry Retry a job
    Re-queue a failed job from its stored source. Past the plan's transcriptions at once it waits its turn (`queue`) behind the account's other queued jobs instead of being refused.
  • POST /v1/recordings/{id}/job/start Start a cropped job
    Release a job waiting in `cropping` (created with `crop: true`): the window of the source to transcribe, in seconds — an omitted bound is the start or the end of the file — then the job is queued. Timestamps in the transcript count from the window's start. Past the plan's transcriptions at once it waits its turn (`queue`) instead of being refused.

languages

  • GET /v1/languages List languages
    Transcription, translation and voice lists with picker metadata.

me

  • GET /v1/me Get the current account
    Who the credential is: the acting principal, the person (`userId`) or API key (`apiKeyId`) behind it, the principals it may act for and a key's scopes.

meta

realtime

  • GET /v1/realtime/capabilities Get realtime capabilities
    What the realtime socket takes: supported languages, audio formats, and limits.
  • POST /v1/realtime/sessions Create a realtime session
    Create a realtime session: a signed, stateless token for one WebSocket (`streamUrl`). Nothing is stored server-side.

recordings

  • GET /v1/recordings/{id} Get a recording
    One recording, by id: for its owner, or any listener who can reach its broadcast or transcription.
  • POST /v1/recordings/{id}/archive Archive a recording
    Archive the recording: hidden, its data kept.
  • GET /v1/recordings/{id}/audio Download a recording's audio
    302 to a freshly signed URL. kind=delivery (owner + listeners, 1 h), voice (a rendered spoken track, needs lang=, owner + listeners, 1 h; through a share link a language other than the spoken one needs the link's `allowTranslate`), source (owner or a link that allows downloads) or master (owner, 5 min). Through a share link EVERY kind needs the link's `allowDownload` — streaming a file and saving it are the same request, so a link with audio off plays nothing either. The delivery is Opus in two containers: format=ogg (default) and format=caf, the one Safari/iOS plays (WebKit rejects or mis-times Ogg); pick by canPlayType('audio/x-caf; codecs=opus'). format=mp3 is for SAVING (delivery and voice): the one container every player opens, encoded on first request and kept (kinds delivery_mp3, voice_mp3:<lang>). The recording's `media` lists which renditions are sealed (kinds delivery, delivery_caf, delivery_mp3); the CAF is remuxed on first request when it is not there yet.
  • GET /v1/recordings/{id}/audio/clip Get an audio clip
    A stretch of the audio as WAV (16-bit, 16 kHz, mono), available while the recording is still open — for replaying a line during live correction. Owner + listeners; at most 120 s. Through a share link it needs the link's `allowDownload`, like every other way of asking for the audio.
  • GET /v1/recordings/{id}/events Get a recording's event log
    The recording's durable event log in order, each frame stamped with the wall time it was written — replays the recording exactly as the host saw it. A page at a time: follow `nextCursor` (absent on the last page) as `cursor`, or start after a `seq` you hold with `after` (not both). Owner only.
  • GET /v1/recordings/{id}/export Export a recording
    A real file: JSON, SRT, XLSX (Excel workbook) or PDF, corrections included. The PDF of a finished recording reads in paragraphs (built by the engine after finalize; a download that finds them missing or stale has them rebuilt first, waiting up to a minute). Owner, a share link (`shareCode`) that allows export, or a listener of its broadcast (`listenerToken`) once the recording has ended. While the job runs the export is partial (file name suffixed, `partial` flagged). `lang` makes the file read in that language — the translation the reader sees on screen, one line per sentence, sentences not yet translated are translated first; the file name carries the language and JSON's `translated` is true. The spoken language, or no `lang`, is the transcript as spoken. A share link with Translate off may only have that.
  • GET /v1/recordings/{id}/media-token Get a media token
    The owner's credential for this recording's media URLs: pass it as `media=` to `/audio`, `/audio/clip` and `/voice/{sentence}` in place of `access_token`. It reads this recording's media and nothing else, and it is the same string for a whole UTC day (valid until the end of the next one) — an access token rotates every few minutes, and a credential in the URL is part of the browser's cache key, so clips fetched with one were fetched again at every rotation.
  • POST /v1/recordings/{id}/pause Pause a recording
    Pause capture. Idempotent.
  • POST /v1/recordings/{id}/publish-token Create a publish token
    Re-attach a publisher (reconnect or another device; takeover=true demotes the current one).
  • POST /v1/recordings/{id}/purge Purge a recording
    Delete an archived recording for good.
  • POST /v1/recordings/{id}/restore Restore a recording
    Bring an archived recording back.
  • POST /v1/recordings/{id}/resume Resume a recording
    Resume a paused recording.
  • PATCH /v1/recordings/{id}/settings Update recording settings
    Mid-recording capture settings (mode, language, labels).
  • PUT /v1/recordings/{id}/speakers/{idx} Name a speaker
    Name a speaker of this recording.
  • POST /v1/recordings/{id}/stop Stop a recording
    End capture; finalize runs asynchronously. Only from paused.
  • POST /v1/recordings/{id}/summarize Request a summary
    Ask for the recording's AI title and summary. The engine writes them after finalize on its own; call this when a finished recording has none (or its pass failed) and poll the recording: `ready` carries them, `pending` means the pass is queued or running, `unavailable` means this server has no summariser.
  • GET /v1/recordings/{id}/summary Get a recording's summary
    The title and summary as they stand — `ready` with both, `pending` while the engine is still writing them, `unavailable` on a server without a summariser. Nothing is queued (that is `summarize`), so a share-link viewer may ask too. `lang` reads them in that language: the one the reader picked on screen, which the transcript and the downloads follow. The engine translates the summary into every language the recording was listened to or read in as it writes it, so those are ready; any other language is translated once, on the first ask, and kept. `lang` in the answer says the translation was had. The spoken language, or no `lang`, is the summary as written. Through a share link a language other than the spoken one needs the link's `allowTranslate`.
  • GET /v1/recordings/{id}/transcript Get a transcript
    Snapshot up to lastSeq; the backfill for subscribers (after=cursor). A line scoring under `settings.confidence.hideBelow` (0.60 by default — the line's own mean word probability, not a count of bad words) is hidden as "Audio unclear". Listeners see it blanked (`suppressed`, text=''); anyone shown the text — the owner, a share-link reader — gets `unclear` instead and keeps every word. Either way the line is spoken to nobody: `GET .../voice/{sentence}` answers 404 for it. Listeners also see translations filtered to lang. Through a share link (`shareCode`), `lang` needs the link's `allowTranslate`: without it any language other than the one spoken is `forbidden`, never a silently untranslated snapshot.
  • GET /v1/recordings/{id}/translation Get a translation
    Sentences of the transcript translated into `lang` (a translation target), by sentence id (`sentences`, comma separated): what a reader in another language pages through. The owner, or any listener who can reach its broadcast or transcription; through a share link it needs `allowTranslate`. A listener's new (recording, language) pairs are limited per network an hour.
  • GET /v1/recordings/{id}/voice Get a recording's voice tracks
    What this recording can be heard speaking, one row per language: rendered tracks (`sealed`) and their jobs, and the per-sentence clips a live audience left behind (`clips`, with the sentence ids and the voice that spoke them). An ended recording has only clips — this is how a listener finds them again and plays its spoken translation back a line at a time. The owner, or any listener who can reach its broadcast or transcription; `lang` narrows it to one. A spoken translation needs the link's `allowTranslate` when reading through a share link — without it the listing carries only the spoken language, and asking for another is `forbidden`.
  • POST /v1/recordings/{id}/voice Render voice tracks
    Render spoken tracks for a finished recording, one job per language (1–10 codes, each one /v1/languages says has a voice). Owner only.
  • GET /v1/recordings/{id}/voice/{sentence} Get a spoken sentence
    One spoken sentence, Ogg/Opus (`format=caf` for Apple's media stack). The owner, or any listener who can reach its broadcast or transcription. A clip in a language the recording was not spoken in is a spoken translation: through a share link it needs `allowTranslate`.

rtmp

  • GET /v1/rtmp Get RTMP status
    The account's RTMP server URL and stream key for an encoder, whether one is sending audio on it right now and what (`audio`, e.g. "48 kHz AAC"), and a signed link to listen to it (`monitorUrl`, an hour). The server URL is RTMPS (TLS) where the server has it; the plain `rtmp://` form on the same host works for encoders without TLS. A live transcription takes it as its source with `source.url` = `serverUrl`. The key is made on first ask, and that answer is the only one with the key in full (`streamKey`): it is kept as a hash, and later answers show `maskedStreamKey`. A lost key is replaced by a reset in the VocalStack app, which revokes the audio links issued before it.

search

  • GET /v1/search Search transcripts
    Sentence search via the English pivot ∪ literal match; results rendered into lang on demand. An owner searches their own transcriptions and broadcasts; a listener names the broadcasts to search by their codes.

share-links

transcriptions

  • GET /v1/transcriptions List transcriptions
    Transcriptions owned by the acting principal (file, link and live), newest first (by `createdAt`), a page at a time: follow `nextCursor` (absent on the last page) as `cursor`. A cursor is never an offset: transcriptions created, changed or archived while you page are neither repeated nor skipped among the rest. `lifecycle=all` is the active and the archived in one list.
  • POST /v1/transcriptions Create a transcription
    Transcribe a file or a link: creates the transcription, its recording and a server-owned job. multipart/form-data with a `file` part (+ optional `options` JSON part), or JSON with `url` (fetched server-side). The source is kept in the media store. Follow the job with `jobs.get`. Never refused for the plan's transcriptions at once: past that limit the transcription is created all the same and its job waits `queued`, with `job.queue`, until one of the account's own transcriptions ends, then starts by itself (the account's jobs in the order they were queued); its charge opens when it starts.
  • POST /v1/transcriptions/live Create a live transcription
    Create a live transcription: captured as it is spoken — this device's microphone, or a stream the server pulls — rather than read from a file (`live: true`). It is created idle; `transcriptions.startRecording` starts it, and the recording's pause / resume / stop calls drive it. `broadcasts` attaches it to those broadcasts from the start.
  • GET /v1/transcriptions/probe Probe a link
    What a link is before it is transcribed: `live` — a YouTube live on air or scheduled, an endless HTTP stream, an HLS playlist with no end, a dynamic DASH manifest — belongs in a live transcription; `file` is transcribed as one; `unknown` could not be told. `source` names the live form's source (`youtube`, `radio`). A web page is not a recording (`ok: false`), but `media` lists the recordings on it — media files, playlists, YouTube videos — each found, then opened as a link of its own would be, with its title on the page when it has one: create one transcription per entry. Nothing is kept. 60 a minute; searching a web page also counts against an hourly allowance — 20 with a plan, 10 on pay as you go, 2 on credit never paid for — and past it the probe answers `rate_limited` with `retryAfterS`.
  • GET /v1/transcriptions/{id} Get a transcription
    One transcription of the acting principal's, by id.
  • PATCH /v1/transcriptions/{id} Update a transcription
    Rename, or update default capture settings.
  • POST /v1/transcriptions/{id}/archive Archive a transcription
    Archive the transcription: hidden, its links dead, its data kept until it is restored or purged.
  • PUT /v1/transcriptions/{id}/broadcasts/{broadcast} Attach a broadcast
    Feed a broadcast from the live transcription `id`: listeners on the broadcast's link read the transcription while it records, and its recordings are listed with the broadcast's own. One transcription can feed several broadcasts, and a broadcast can be fed by several. Returns the transcription.
  • DELETE /v1/transcriptions/{id}/broadcasts/{broadcast} Detach a broadcast
    Stop feeding the broadcast from the live transcription `id`. Returns the transcription.
  • POST /v1/transcriptions/{id}/purge Purge a transcription
    Delete an archived transcription and everything in it, for good.
  • GET /v1/transcriptions/{id}/recordings List a transcription's recordings
    The transcription's recordings, newest first, a page at a time: follow `nextCursor` (absent on the last page) as `cursor`. `lifecycle=archived` lists the archived ones.
  • POST /v1/transcriptions/{id}/recordings Start a recording
    Start recording a live transcription and mint a publisher realtime session (`streamUrl`, `sessionId`). 409 conflict with details.takeover when another device is recording. When its source is a stream URL the server pulls the URL and publishes it itself: the grant carries no `streamUrl`, and `recording.ingest` (plus `stream.ingest` frames) says where it stands. `scriptText` gives the recording words to follow like a teleprompter (`Recording.scriptText`).
  • POST /v1/transcriptions/{id}/recordings/upload Upload a recording
    A file or link recording in this transcription: no live phase, transcribed at full speed.
  • POST /v1/transcriptions/{id}/restore Restore a transcription
    Bring an archived transcription back.
  • GET /v1/transcriptions/{id}/share-links List a transcription's share links
    Active share links of the transcription.
  • POST /v1/transcriptions/{id}/share-links Create a share link
    A named link ("Who is it for?") to the read-only public page. `allowDownload`, `allowExport` and `allowTranslate` are all on by default and per link. Send `allowTranslate: false` to close a link to translation; it takes effect from the next request.

voices

  • GET /v1/voices List voices
    The account's cloned voices, newest first.
  • POST /v1/voices Create a voice
    Create a voice from a recorded sample and queue its training: multipart/form-data with a `sample` audio part and a `meta` JSON part. The voice comes back `training` with progress 0; poll GET /v1/voices/{id}. Training reports a real state — it never fakes progress, and a voice that cannot be trained ends `failed` with the reason on `error`.
  • GET /v1/voices/available List available voices
    The voices that can speak a language, best first (`default` marks the one a recording that pins none gets). Open to listeners; a bearer token also returns that account's ready cloned voices. A clip is synthesised once per language and fanned out, so this is the set a host may pin in `settings.voiceByLang` — and all a listener can ever be offered.
  • POST /v1/voices/from-speaker Create a voice from a speaker
    Create a voice from one speaker of a recording — no sample to upload, because the recording's own audio is the sample. Works while the recording is still running: the server joins the stretches that speaker actually spoke for and clones from those. Naming them here also labels them in the transcript and associates them with the new voice. Needs at least 30 seconds of them; the refusal says how much there is.
  • GET /v1/voices/preview Preview a voice
    A few seconds of a voice speaking a language, Ogg/Opus (`format=caf` for Apple's media stack). Only voices the catalogue offers can be previewed.
  • GET /v1/voices/{id} Get a voice
    Training state: `training` / `ready` / `failed`, with `progress` and, when it failed, `error`.
  • PATCH /v1/voices/{id} Update a voice
    Rename a voice, recolour it, or switch it off. Absent fields are left alone; `color: ""` clears a chosen colour. Not the place to withdraw permission — that deletes the voice.
  • DELETE /v1/voices/{id} Delete a voice
    Delete the voice, its recorded sample and anything trained from it.
  • GET /v1/voices/{id}/preview Preview a cloned voice
    The cloned voice speaking, Ogg/Opus — `format=caf` for Apple's media stack, which will not play Ogg. 409 while it is not `ready`. The owner's token may ride in `access_token`, because an `<audio>` element cannot carry a header.
  • GET /v1/voices/{id}/sample Get a voice's sample
    The audio this voice was made from, for its owner alone. Ranged. It is what lets a draft picked up after a reload be the screen that was left — take, waveform and playback — rather than a preview of one.