# MoneyTools Transcripts > MoneyTools Transcripts: value-added transcript and subtitle generation for agents — timestamped segments, SRT and VTT subtitles, language detection, word count and duration, optional short summary. Accepts media you have the right to process (direct file URLs, signed one-time uploads, or base64: WAV/MP3/M4A/MP4/WebM/OGG/FLAC). Platform page URLs (YouTube, Instagram, TikTok, etc.) are refused. 0.002 USDC per started audio minute via x402 on Base USDC; sync POST /v1/speech/transcribe has a 0.003 USDC per-call minimum, async jobs have no extra minimum (1 started minute = 0.002 USDC). Speaker diarization is NOT supported (segments carry speaker:null). Free quote. Free: 3 short jobs/day per client. Max 10 min / 25 MB per sync call; long files: async jobs up to 180 min / 100 MB (MP3/WAV segmented) at 0.002 USDC per started minute, poll or signed webhook; dTelecom-compatible POST /v1/transcriptions/jobs (multipart file or url) with no prepaid credits. Not sold as raw speech-model API access. ## Start 1. Free quote: GET https://speech.moneytools.dev/v1/speech/quote?minutes=3 2. Local file (remote MCP agents): POST https://speech.moneytools.dev/v1/speech/upload-url (or MCP speech_upload_url) → PUT bytes to the signed URL → POST /v1/speech/transcribe with `{upload_id}`. 3. Or transcribe with JSON `{url}` / `{audio_base64}` / multipart `file` → free (3/day) or HTTP 402 + PAYMENT-REQUIRED (x402 v2, exact, Base USDC, payTo 0x64eB63904Cf9688AC5B3087A72AcF9C31a273169). 4. Optional fields: `language`, `summary` (bool), `durationSeconds` (hint only — cannot underprice; we parse the container). 5. MCP: https://speech.moneytools.dev/mcp — speech_upload_url (free), speech_quote (free), speech_transcribe, speech_report (paid), speech_job_upload_url / speech_job_submit / speech_job_status (long files). ## Long files: async jobs (0.002 USDC per started minute, up to 180 min / 100 MB) 1. Price check (free): GET https://speech.moneytools.dev/v1/speech/quote?minutes=60 → `asyncJob.amountUsd` (60 min = 0.120 USDC). 2. Either POST https://speech.moneytools.dev/v1/speech/jobs `{"url":"https://…/episode.mp3","webhook":"https://your.app/hook"}`, or POST https://speech.moneytools.dev/v1/speech/jobs/upload-url → PUT the bytes → POST https://speech.moneytools.dev/v1/speech/jobs `{"upload_id":"job_…"}`. 3. You get HTTP 402 with the **exact** price for that file (MP3 frames / WAV samples are counted; declared duration can only raise it). Retry the same request with PAYMENT-SIGNATURE. 4. We transcribe the first ~5-minute segment **before** settling (unreadable files are never charged), then answer 202 `{jobId, jobToken, statusUrl}`. 5. Poll GET https://speech.moneytools.dev/v1/speech/jobs/{jobId} with `Authorization: Bearer ` every ~15 s. `?format=json` (default: status + result {text, segments[{start,end,text}], language, wordCount, srt, vtt, durationSeconds, summary?}), `?format=srt|vtt|txt` for raw subtitles/text, or wait for the webhook (header `X-Transcripts-Signature: t=…,v1=HMAC_SHA256(webhookSecret, "t.body")`). 6. MP3 and PCM WAV are split into ~5-minute segments; M4A/MP4/WebM/OGG/FLAC are processed as one segment up to 10 min (convert longer ones to MP3). If the daily audio-minute capacity is used up, the job **waits** and continues after 00:00 UTC (status `waiting_capacity`); it is never dropped. Results are kept 24 h. 7. MCP: speech_job_upload_url (free) → speech_job_submit (paid, PaymentRequired → _meta["x402/payment"]) → speech_job_status (free). ## dTelecom-compatible file transcription (0.002 USDC per started minute, no prepaid credits) Same shape as dTelecom's `/v1/transcriptions/jobs`, but paid per file directly via x402 — no credit purchase, no wallet-auth headers. 1. `curl -i -X POST https://speech.moneytools.dev/v1/transcriptions/jobs -H 'Idempotency-Key: meeting-42' -F file=@meeting.mp3 -F language=en` (or JSON `{"url":"https://…/meeting.mp3"}`) → HTTP 402 with the exact price for that file + `{id, status:"payment_required", duration_seconds}`. 2. Resend the same request (same Idempotency-Key: the stored upload is reused, not reread) with PAYMENT-SIGNATURE → 202 `{id, status:"running", duration_seconds, job_token, status_url}`. 3. GET https://speech.moneytools.dev/v1/transcriptions/jobs/{id} with `Authorization: Bearer ` (or dTelecom's EVM wallet-auth headers signed by the wallet that paid) → `{id, status: queued|running|completed|failed, duration_seconds, result:{text, language, segments:[{start,end,speaker,text}], media:{sample_count,sample_rate,channels,duration_seconds}, speaker_segments, timing_type, srt, vtt}}`; `?format=json|srt|vtt|txt`. DELETE cancels/removes artifacts. 4. Differences: `diarize` is accepted but speaker diarization is **not available** (speaker:null, speaker_segments:[]); language defaults to auto-detect; up to 180 min / 100 MB (segmented: MP3/WAV); results kept 24 h; optional `webhook` field. ## Migrate from dTelecom (base URL change, no prepaid credits) Full guide with curl / Python / TypeScript, SDKs and benchmark: https://speech.moneytools.dev/docs/migrate-from-dtelecom (markdown: https://speech.moneytools.dev/docs/migrate-from-dtelecom.md; also https://speech.moneytools.dev/migrate/dtelecom). Keep the official @dtelecom/x402-client: set `gatewayUrl: "https://speech.moneytools.dev"`, add one line `installTranscriptsFetch(account)` (package @moneytools/transcripts, pre-release) so each file's 402 is paid; polling with its wallet-auth headers works for the paying wallet. Native: `TranscriptsGateway` (TS) / `TranscriptsClient` (Python, moneytools-transcripts) with the same method names. Benchmark 2026-11-10 (3 public-domain LibriVox readings, our engine + whisper-large-v3-turbo): WER 0.9% / 1.9% / 5.4%; processing 2.8 s for 1.5 min, 6.2 s for 2.7 min, 31.3 s for 9.5 min. Details and caveats on the docs page. Runnable examples: https://speech.moneytools.dev/examples/transcribe.py · https://speech.moneytools.dev/examples/transcribe.ts · https://speech.moneytools.dev/examples/transcribe.sh · https://speech.moneytools.dev/examples/x402_sign.py ```diff - BASE = "https://x402.dtelecom.org" + BASE = "https://speech.moneytools.dev" - await gw.buyCredits({ amountUsd: 0.10 }) // prepaid credits: gone - headers: Authorization/X-Wallet-Address/X-Wallet-Chain/X-Timestamp // wallet-auth headers: gone + payFetch = wrapFetchWithPayment(fetch, x402Client) // pays the exact 402 for each file POST /v1/transcriptions/jobs multipart: file, language, diarize + Idempotency-Key (unchanged) GET /v1/transcriptions/jobs/{id} (unchanged path) poll auth: wallet signature headers from the paying wallet (still accepted, EVM) + or: Authorization: Bearer (returned once in the 202) DELETE /v1/transcriptions/jobs/{id} (unchanged) ``` - Python: `pip install "x402[requests,evm]" eth-account` → `x402_requests(client).post(DT_URL, files={"file": …}, headers={"Idempotency-Key": k})` → 202 → poll `status_url` with Bearer job_token. - TypeScript: `npm i @x402/fetch @x402/evm viem` → `wrapFetchWithPayment(fetch, new x402Client().register("eip155:8453", new ExactEvmScheme(account)))` → same POST (FormData) → poll. - Not the same: no speaker diarization; billed per started minute; 100 MB / 3 h max; live daily capacity at https://speech.moneytools.dev/health (`usage`). ## How to pay (x402 v2, USDC on Base) — sync transcribe from 0.003 USDC/call (0.002 USDC/started min); async jobs 0.002 USDC/minute 1. Call without payment: curl -i -X POST 'https://speech.moneytools.dev/v1/speech/transcribe' -H 'content-type: application/json' -d '{"url":"https://example.com/audio.mp3"}' → HTTP 402, header PAYMENT-REQUIRED (base64 JSON; same JSON in the body: accepts[] with scheme exact, network eip155:8453, asset USDC, amount, payTo). 2. Sign one accepts[] entry (EIP-3009 TransferWithAuthorization) with your wallet and resend the same request with header PAYMENT-SIGNATURE: base64({"x402Version":2,"accepted":{…},"payload":{"signature":"0x…","authorization":{"from","to","value","validAfter","validBefore","nonce"}}}). (v1 clients: X-PAYMENT.) 3. 200 + PAYMENT-RESPONSE header = paid. Failed calls are not settled. Malformed payment header → HTTP 400 {error: invalid_payload | invalid_exact_evm_payload_signature | …}. JS (any x402 client works): import { wrapFetchWithPayment } from "@x402/fetch"; // + your viem/CDP signer const pay = wrapFetchWithPayment(fetch, signer); const r = await pay("https://speech.moneytools.dev/v1/speech/transcribe", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({"url":"https://example.com/audio.mp3"}) }); Python: x402 package (x402.clients.requests / httpx) wraps requests the same way. MCP: an unpaid paid-tool call returns isError + structuredContent = PaymentRequired; resend tools/call with params._meta["x402/payment"] = the PaymentPayload object; receipt in result._meta["x402/payment-response"]. Async job example: same flow on POST https://speech.moneytools.dev/v1/speech/jobs with `{"url":"https://example.com/episode.mp3"}` or POST https://speech.moneytools.dev/v1/transcriptions/jobs (multipart `file`) — 402 amount = 0.002 USDC/minute x started minutes, no minimum. ## Media you have the right to process - **Allowed:** direct media file URLs, signed one-time uploads, or base64 — WAV, MP3, M4A, MP4, WebM, OGG, FLAC (Content-Type audio/* or video/*, or octet-stream with valid magic bytes). - **Refused:** YouTube, youtu.be, Instagram, TikTok, Facebook, X/Twitter, Vimeo and other platform **page** URLs (`platform_url_not_supported`, no download attempted). - Signed uploads are **not** public hosting: single-use, ~15 min TTL, deleted after transcription or expiry. ## What you get (value-add) - Full text transcript, timestamped segments, SRT + VTT, language detection, word count, duration, optional short summary. - This is a **transcript/subtitle generation service**, not raw speech-model API access. ## Billing rule Billed minutes = started minutes of max(declared duration, parsed container duration, **16 kbps size floor**) — the size floor always applies even when a header parses. Failed jobs are never settled. Real minimum per endpoint: - Sync POST /v1/speech/transcribe (MCP `speech_transcribe`): max(0.003, 0.002 × started minutes) USDC → **minimum 0.003 USDC per call** (a 1-minute file costs 0.003; 2 minutes 0.004). - Async POST /v1/speech/jobs, dTelecom-compatible POST /v1/transcriptions/jobs (MCP `speech_job_submit`): 0.002 × started minutes, **no extra minimum** → smallest charge 0.002 USDC (1 started minute). - MCP `speech_report`: flat 0.001 USDC. `speech_quote` and upload URLs are free. ## Not supported - **Speaker diarization is not supported** on any endpoint. `diarize` is accepted for dTelecom compatibility but ignored: segments carry `speaker: null`, `speaker_segments: []`, and the response includes `diarization: {requested: true, available: false}`. ## Limits (Workers Free) - Sync: max 10 minutes / 25 MB per call. Async jobs: up to 180 minutes / 100 MB. - Global ~180 audio minutes/day shared — sync over cap returns HTTP 503 `daily_capacity_reached` without charging; paid async jobs wait and resume after 00:00 UTC. ## Links - OpenAPI: https://speech.moneytools.dev/openapi.json · x402: https://speech.moneytools.dev/.well-known/x402 · MCP: https://speech.moneytools.dev/mcp