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), 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`), 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 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. 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. 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). Both need `acceptTerms: true` and `waiveWithdrawal: true` (credit is not refundable; performance starts at once) or the request is `422 invalid_body`. 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. 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.
  • 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. 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`).
  • GET /v1/billing/plans List the plans
    The visible plans with their current rates, 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.
  • 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`).

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.
  • 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.

corrections

  • POST /v1/corrections/{id}/revert Revert a correction
    Undo one correction.
  • GET /v1/recordings/{id}/corrections List corrections
    Every correction made to the recording's transcript.
  • 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).
  • 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.
  • 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.

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. 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, or a share link (`shareCode`) that allows export. 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). A live transcription takes it as its source with `source.url` = `serverUrl`. The key is made on first ask.

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). `lifecycle=all` is the active and the archived in one answer, up to 500 of each.
  • 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`.
  • 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`). Nothing is kept. 60 a minute.
  • 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.
  • 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.