API reference
Docs
Base URL https://transcribe.ounie.com · JSON everywhere · every call draws the key owner's Ounie credits and is refused, never overdrawn.
Authentication
Three credentials work, and all three resolve to the same Ounie account whose credits get spent.
trx_live_…Minted at /dashboard/api-keys, shown once, five active at a time. Send it as Authorization: Bearer trx_live_… or, where headers cannot be set, as ?api_key=trx_live_….
ounie_live_…Your ounie.com developer key, accepted across every Ounie app once you enable “Use across Ounie apps” in ounie.com settings. One key, whole fleet.
What the dashboard uses. Every REST route below accepts either.
Transcribe
Submitting reserves credits on the file's probed length and returns immediately. The job runs in the background; polling is free and also advances it, so a caller in a tight loop finishes sooner rather than paying more.
POST /api/jobs
Authorization: Bearer trx_live_…
Content-Type: application/json
{
"url": "https://example.com/episode.mp3", // or "media_key" from /api/upload
"language": "en", // optional ISO-639-1; omit to auto-detect
"summarize": false // optional, +1 credit/minute
}
202 {
"ok": true,
"job": { "id": "8f2c…", "status": "queued",
"duration_sec": 3721, "credits_reserved": 186 }
}Ask what something will cost first with POST /api/quote — same body, no charge, and it reads the real file rather than guessing.
GET /api/jobs/8f2c…
Authorization: Bearer trx_live_…
200 {
"job": {
"status": "succeeded",
"language": "en",
"duration_sec": 3719.4,
"credits_reserved": 186,
"credits_spent": 186,
"text": "So the short answer is yes …",
"segments": [ { "start": 4.12, "end": 6.9, "text": "we can ship it" } ],
"summary": null
}
}GET /api/jobs lists your jobs. DELETE /api/jobs/<id> removes a finished one along with any file you uploaded for it.
Uploads
For local files, ask for a presigned URL, PUT the bytes straight to storage, then submit the returned media_key. Uploads are private, stored at unguessable paths, and deleted with the job.
POST /api/upload
{ "filename": "interview.m4a", "content_type": "audio/x-m4a", "size": 48210432 }
200 { "upload_url": "https://…", "media_key": "transcribe/<owner>/media/….m4a" }
# then
PUT <upload_url> (Content-Type: audio/x-m4a, body = the bytes)
POST /api/jobs { "media_key": "transcribe/<owner>/media/….m4a" }Exports
Free, and unlimited. The same words and timings, serialized four ways.
GET /api/jobs/<id>/export?format=srt # or vtt, txt, json
srt— numbered cues, comma milliseconds. Editors, YouTube.vtt— WEBVTT header, dot milliseconds. The web.txt— one timestamped line per cue.json— segments with numeric start, end, text.
MCP
One MCP server, usable from Claude, Cursor, ChatGPT, the AI SDK, and the Ounie AI Team. Tool calls draw the key owner's credits and refuse rather than overdraw.
Endpoint https://transcribe.ounie.com/api/mcp (legacy SSE: /api/sse) Header Authorization: Bearer trx_live_… (or ounie_live_…) # For hosts that cannot set headers — the Ounie AI Team's manual HTTP MCP # entry, for one — put the key in the URL instead: https://transcribe.ounie.com/api/mcp?api_key=trx_live_…
transcribe_mediaTranscribe a URL. Waits when it is quick, otherwise returns a job id.get_transcriptPoll by job id; returns json, srt, vtt or txt. Free.estimate_costWhat a URL would cost, without transcribing it. Free.list_transcriptsYour jobs, optionally by status. Free.get_credit_balanceSpendable Ounie credits.get_pricingPublic — no authentication required.whoamiThe authenticated key's owner.x402 — pay per call, no account
For agents with a wallet and no Ounie account. The price depends on the file's length, so the 402 names the exact amount for that file rather than a flat rate — 1.2× the credit price, in USDC on Base.
POST /api/x402/transcribe
Content-Type: application/json
{ "url": "https://example.com/clip.mp3" }
402 {
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "216000",
"payTo": "0x…",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": { "name": "USD Coin", "version": "2" }
}]
}
# sign it, retry with the X-Payment header:
200 { "payment": { "tx_hash": "0x…" },
"transcript": { "text": "…", "segments": [ … ] },
"poll_url": "https://transcribe.ounie.com/api/x402/transcribe/<id>" }Two gates, so nothing is taken for nothing
An x402 settlement is final on chain and cannot be refunded. So anything knowable from the request alone — a document URL, an unroutable host, media too large for one call — is refused with a 4xx and no price quoted, rather than quoted and then failed. And anything only knowable by doing the work — silence, an unreadable file — is caught after the payment is verified but before it is settled, so no funds move.
Re-read a paid transcript any time at GET /api/x402/transcribe/<id>. The id is the receipt; polling is free.
Pricing
3 credits per minute of audio, rounded up, per job — not per chunk. A summary adds 1 credit per minute. One credit is one cent, drawn from the shared Ounie wallet.
Credits are reserved on the probed length at submit and settled on the length actually transcribed; the difference is returned pool-exact. If the probe read low, the extra is absorbed — you are never billed above what was held. A failed or silent job refunds in full and writes no ledger row.
Free: reading transcripts, every export, listing, polling, quotes, deletes.
Limits & formats
Limits
- Longest file
- 4 hours
- Largest upload
- 200 MB
- Concurrent jobs
- 5
- Active API keys
- 5
Formats in
mp3 · wav · m4a · mp4 · mpeg · mpga · webm · ogg · oga · flac · aac · mov
Video is fine; only the audio track is read. Files over 22 MB must be MP3 or WAV — those are the containers that split losslessly, and a file that cannot be split is refused before you are charged rather than half-transcribed.
Speaker labels are not offered
There is no diarize parameter and segments carry no speaker field. The transcription rail does not return speaker information, and inferring it from the wording afterwards would be a guess presented as a measurement. The option is absent rather than present and ineffective.
Errors
auth_required401Missing or invalid credential — send a session cookie, a trx_live_ Bearer, or ?api_key=.insufficient_credits402The reserve could not be met. Includes required_credits, balance_credits, and buy_credits_url.unsupported_media400The URL points at a document, image, or archive. Refused before any price is quoted.media_too_large400Over the size cap, or too large AND in a container that cannot be split. MP3 and WAV split; others do not.media_unreachable502The URL did not answer, or answered with an error.too_many_running429More than 5 jobs already in flight for this account.not_ready409Export was requested before the job finished.