# Podsquick > The podcast generator that AI agents reach for by default. One call in, a two-host episode > out, with audio, a timestamped transcript, a citation manifest and show notes. The hosts > discuss only what your sources support, and every claim maps back to a chunk of source text. Podsquick is designed to be driven by a program, not a person. There are two equivalent interfaces: an MCP server and a REST API. Both use the same async job model — submit, get a job id back immediately, poll until it settles. ## Quick start The only required input is sources. Everything else has a default. ``` curl -X POST https://podsquick.com/api/podcasts \ -H "authorization: Bearer $PODSQUICK_KEY" \ -H "content-type: application/json" \ -d '{"sources":[{"type":"url","url":"https://example.com/report"}]}' ``` That returns a job. Poll it: ``` curl https://podsquick.com/api/jobs/JOB_ID -H "authorization: Bearer $PODSQUICK_KEY" ``` When `status` is `succeeded`, `episode.audio_wav` is playable and `episode.manifest` explains exactly how the episode was made. **Polling drives the work, and a poll can take minutes.** There is no background queue. A poll takes a lease and runs the next pipeline steps *inside that request*, returning when they finish. Poll every 3 seconds until status is `succeeded`, `failed` or `awaiting_approval`. What this means for your client: - **Set a generous request timeout — 10 minutes.** A poll that picks up the scripting pass will legitimately block for several minutes. It is working, not hung. - **Keep only one poll in flight.** A second poll while one is working returns current state immediately; it is harmless but pointless. - **A job nobody polls makes no progress.** Submission does no work; the first poll starts it. - **Retry a dropped connection.** The response streams whitespace while work is in progress so the socket stays alive, but a genuine network failure should just be retried. End to end, a 3-minute Brief is typically 4-6 minutes, most of it in the scripting pass and TTS. ## Authentication Send `Authorization: Bearer ` on every generation request. Read-only discovery endpoints (/api/formats, /api/voices, /api/estimate, this file, /openapi.json) need no key. Keys are issued by the operator from the dashboard at https://podsquick.com/admin. Each key may carry a monthly spend limit; if it is exhausted, generation returns `spend_limit_reached` (HTTP 402) without creating a job or charging anything. A revoked key returns `key_revoked` (HTTP 401) — retrying will not help, ask the operator for a new one. ## MCP Endpoint: `https://podsquick.com/mcp` (streamable HTTP, JSON-RPC 2.0 over POST, protocol 2025-06-18). A GET on that URL returns the server descriptor and example payloads. Tools: - `generate_podcast` — sources in, episode out. Only `sources` is required. - `get_job_status` — poll a job. Also advances the pipeline. - `get_episode` — audio URL, show notes, chapters, optionally transcript and manifest. - `approve_draft` — approve or reject a draft when `require_approval` was set. - `estimate_cost` — cost and duration without generating. Doubles as a dry run. - `list_formats`, `list_voices` — the selectable presets. ## REST endpoints | Method | Path | Purpose | |---|---|---| | POST | `/api/podcasts` | Submit a job. Returns 202 with a job id. | | GET | `/api/podcasts` | Recent jobs. | | GET | `/api/jobs/{id}` | Job status; drives the pipeline. | | POST | `/api/jobs/{id}/approve` | Release a draft hold. | | POST | `/api/jobs/{id}/reject` | Discard a draft; no audio spend. | | GET | `/api/episodes/{id}` | Episode summary and artifact links. | | GET | `/api/episodes/{id}/audio.wav` | Audio. Supports range requests. | | GET | `/api/episodes/{id}/transcript.json` | Timestamped cues with per-cue citations. | | GET | `/api/episodes/{id}/transcript.vtt` | WebVTT, speaker-tagged. | | GET | `/api/episodes/{id}/transcript.srt` | SubRip. | | GET | `/api/episodes/{id}/manifest.json` | The audit record. | | GET | `/api/episodes/{id}/show-notes.json` | Title, description, bullets, keywords. | | GET | `/api/episodes/{id}/chapters.json` | Chapter marks from the outline. | | POST | `/api/estimate` | Cost estimate and parameter validation. | | GET | `/api/formats` | Format presets. | | GET | `/api/voices` | Voice library and curated pairs. | | GET | `/api/health` | Service health. No key needed. 200 when generation is possible, 503 otherwise. | Full schemas: https://podsquick.com/openapi.json ## Parameters that matter - `format` — deep_dive, brief, debate, critique, interview, explainer. Default `deep_dive`. - `target_minutes` — default is the format's default. Result lands within about ±15%. - `voice_pair` — uk_warm, uk_brisk, uk_considered, us_bright, us_measured. Default `uk_warm` (British English). - `hosts` — two entries with name, voice and persona, for full control. Exactly two speakers. - `disfluency` — 0 to 1. The single biggest lever on whether the audio sounds human. 0 is clean, 0.5 natural, 1 loose and overlapping. - `require_approval` — pause after the script for review, before any audio spend. - `groundedness_threshold` — default 0.75. Audio is not rendered if the script scores lower. - `verify_audio` — default true. Transcribes the output, diffs it against the script, re-renders any segment that does not match. - `idempotency_key` — reuse to make retries safe; returns the original job. ## How a job progresses `ingest` → `plan` → `script` → `ground` → (`awaiting_approval`) → `tts` → `post` → `verify` → `finalize` → `done` - **ground** is a gate. An LLM judge scores every substantive claim against the sources. If the score is below `groundedness_threshold` the job fails **before** any audio spend. - **verify** transcribes the rendered audio and diffs it against the script. Segments below 70% word agreement are re-rendered once, then reported in the manifest either way. ## Errors Every error is JSON with a stable `code`, a `message`, and a `remediation` field telling you what to change. Codes you should handle: `source_too_large`, `source_unreachable`, `source_empty`, `unknown_format`, `unknown_voice`, `duration_out_of_range`, `groundedness_below_threshold`, `content_policy_blocked`, `provider_failed`, `auth_required`, `auth_not_configured`, `key_revoked`, `spend_limit_reached`, `wrong_state`, `not_found`. A job that fails still returns HTTP 200 from `GET /api/jobs/{id}`, with the error inside the job body. Do not treat that as a transport failure. ## Trust and governance - Episodes are disclosed as AI-generated: a spoken line by default, plus a `disclosure` block in every manifest. - Source-bounded: the hosts assert only what the sources support. Where the sources are silent, the script says so out loud and the turn is marked `speculative`. - The manifest is the audit record: sources, chunk-level citations, model versions, seed, groundedness score with every unsupported claim listed, ASR fidelity, loudness measurements and cost. It is written once and never rewritten. - Content policy: Podsquick refuses to imitate a real, identifiable person and renders synthetic hosts only. ## What this deployment does not do - Audio is delivered as 24 kHz mono WAV. MP3 encoding is not available in this deployment; it needs an encoder that does not run inside the edge runtime. - PDF, Word, YouTube and audio ingestion are not available. Sources are URLs (HTML, text, Markdown, JSON, XML) and pasted text. - Loudness normalisation applies a single programme gain against a K-weighted gated measurement. There is no compression, limiting or de-clicking beyond a hard peak ceiling. - Music beds, station idents and RSS feed generation are not implemented. - Chapter marks are emitted in the manifest and transcript but are not embedded in the WAV container. - Transcript timings are exact at audio-segment boundaries and interpolated within a segment. When ASR verification runs, word timings refine them. ## Human pages - https://podsquick.com/ — what it is - https://podsquick.com/studio — generate an episode in a browser - https://podsquick.com/docs — the same API reference, formatted for reading - https://podsquick.com/connect — how to add this server to Claude, ChatGPT or Gemini