Read text from the command line
Telereader has a small HTTP API for turning text into a narrated reading. Everything works from curl — no SDK or CLI required. You onboard once, then every submit returns a URL you can open and hear. A free caller is never dead-ended: you always get back an openable URL.
Base URL: https://telereader.ai
Step 1 — onboard once
The API uses the OAuth device grant (RFC 8628): the tool asks for a code, a human approves it in their browser, and the tool gets a token. You do this once and reuse the token.
# (a) ask for a code
curl -s -X POST https://telereader.ai/api/auth/device/code \
-H 'content-type: application/json' -d '{"client_id":"tlread"}'
# → {"user_code":"WXYZ-1234",
# "verification_uri_complete":"https://telereader.ai/device?user_code=WXYZ-1234",
# "device_code":"…","interval":5,"expires_in":900}Open the verification_uri_complete in a browser, sign in if asked, and approve. Meanwhile, poll for the token:
# (b) poll every `interval` seconds until approved
curl -s -X POST https://telereader.ai/api/auth/device/token \
-H 'content-type: application/json' \
-d '{"grant_type":"urn:ietf:params:oauth:grant-type:device_code","device_code":"<device_code>","client_id":"tlread"}'
# pending → {"error":"authorization_pending"} (keep polling)
# approved → {"access_token":"<TOKEN>","token_type":"Bearer",...}Save <TOKEN>. Reuse it for every future call.
Step 2 — submit text, get an openable URL
curl -s -X POST https://telereader.ai/api/v1/readings \
-H "Authorization: Bearer <TOKEN>" -H 'content-type: application/json' \
-d '{"source":{"kind":"markdown","body":"# Title\n\nThe text to read aloud."}}'Returns 202 immediately with a readUrl. Open it and it plays — text on screen, in sync with the narration.
- Free / over-cap: {"mode":"browser","readUrl":"…"} — the URL generates the audio in the browser. Hand it to the human or open it.
- Paid + headroom: {"mode":"server","readingId":"…","readUrl":"…","pollUrl":"…"} — the audio renders on our servers. **Open readUrl immediately** — it streams as it generates, so hand it over right away; don't wait for generation to finish. Polling pollUrl for status is optional (only if you want to show progress).
A free caller is never returned a bare 402 — you get a browser readUrl instead.
The request body
source is the only required field:
- {"kind":"text","body":"…"} or {"kind":"markdown","body":"…"} (≤ 1,000,000 characters)
- {"kind":"url","url":"https://…"} or {"kind":"upload",…} — Telereader fetches + extracts + cleans the page/document for you, so you don't have to. Import is a paid feature: free callers get 402 (paid_feature) — fetch the text yourself and submit it directly instead.
Optional: voice, title, ephemeral, idempotencyKey. Re-submitting the same content with the same key is idempotent (one reading). You can also pass the key as a header: -H "Idempotency-Key: <key>".
Errors
Every error is { "error": <code>, "message": … }:
| HTTP | code | what to do |
|---|---|---|
| 401 | unauthorized | onboard (Step 1) and send the Bearer token |
| 400 | validation_failed | fix the body (carries zodError) |
| 429 | rate_limited | wait Retry-After seconds, then retry |
| 422 | extraction_failed | url/upload import failed — submit text instead |
| 5xx | internal_error | our side — grab the trace id and offer to report it (below) |
Every response carries a trace id — the **x-trace-id response header, also mirrored into the JSON body as traceId**. On a 5xx, quote it to the user and offer to file a bug: POST /api/auth-authenticated multipart/form-data to /api/bug-report with a note like "[trace: <x-trace-id>] <what happened>". (An agent should ask first: "Telereader had a problem — I have a request id, want me to report it?")
Generate a client — don't hand-roll
The full machine-readable spec lives at [/api/v1/openapi.json](https://telereader.ai/api/v1/openapi.json) — a complete OpenAPI 3.0 document (onboard + submit + poll + delete). Point your generator at it rather than hand-writing a client.
If you're wiring up an AI agent rather than a script, see Use Telereader from an agent.