API Documentation
Base URL: https://podscriptapi.com/api
Authentication
Create an API key in the dashboard and pass it as a bearer token on every request:
Authorization: Bearer psk_live_...
Credits
- Any transcript request: 15 credits, flat, regardless of episode length
- Lookup, search, episode list: 1 credit
- Fetching a transcript by id (
GET /v1/transcripts/:id) and/v1/me: free - Failed transcriptions are automatically refunded
- Responses with status 4xx/5xx never consume transcript credits
- Episodes longer than 8 hours are rejected with
422
Endpoints
POST/v1/transcripts
The main endpoint. Give it any podcast link — Spotify episode, Apple Podcasts episode, RSS feed, Pocket Casts, Overcast — and get a transcript. Returns 200 with the transcript when it is available immediately (cache hit or publisher transcript), or 202 with status: "processing" when a fresh transcription was started.
curl -X POST https://podscriptapi.com/api/v1/transcripts \
-H "Authorization: Bearer psk_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://podcasts.apple.com/us/podcast/x/id1200361736?i=1000634975305",
"webhook_url": "https://yourapp.com/hooks/transcript"
}'Body parameters:
url(required) — episode or feed URL from any supported platformepisode.guid/episode.title— pick a specific episode whenurlis an RSS feedwebhook_url— we POST{event: "transcript.finished", data: {...}}when an async job completes
GET/v1/transcripts/:id
Fetch a transcript by id. Poll this after a 202, or use webhooks. Free to call. Use ?format=json|text|srt|vtt.
curl "https://podscriptapi.com/api/v1/transcripts/{id}?format=srt" \
-H "Authorization: Bearer psk_live_..."GET/v1/lookup
Resolve any podcast link to canonical metadata (show, episode, audio URL, whether a publisher transcript exists) without transcribing. 1 credit.
curl "https://podscriptapi.com/api/v1/lookup?url=https://open.spotify.com/episode/..." \ -H "Authorization: Bearer psk_live_..."
GET/v1/search
Search 4M+ podcasts by name. 1 credit.
curl "https://podscriptapi.com/api/v1/search?q=lex%20fridman" \ -H "Authorization: Bearer psk_live_..."
GET/v1/episodes
List a show's episodes with ?feed_id= (from search results) or ?feed_url=. Includes has_rss_transcript so you can predict costs. 1 credit.
GET/v1/me
Your plan and remaining credits. Free.
The transcript object
{
"id": "uuid",
"status": "completed" | "processing" | "failed",
"source": "cache" | "rss_native" | "asr",
"language": "en",
"duration_sec": 3812,
"show": { "id", "title", "author", "rss_url" },
"episode": { "id", "title", "guid", "published_at", "audio_url" },
"text": "Full transcript text...",
"segments": [
{ "start": 0, "end": 4200, "speaker": "Speaker A", "text": "..." }
],
"created_at": "...", "completed_at": "..."
}start/end are milliseconds. speaker is present when the source provides it (publisher transcripts with speaker names, or diarization-capable transcription). Transcripts without timing data have start: 0, end: 0.
Errors
401— missing or invalid API key402— not enough credits (the response says how many are needed)404— episode could not be resolved (e.g. platform-exclusive shows)422— episode resolved but has no public audio429— rate limit exceeded for your plan503— an upstream directory or transcription provider is temporarily down; retry with backoff
Python example
import requests, time
API = "https://podscriptapi.com/api"
HEADERS = {"Authorization": "Bearer psk_live_..."}
r = requests.post(f"{API}/v1/transcripts", headers=HEADERS,
json={"url": "https://open.spotify.com/episode/..."})
job = r.json()
while job["status"] == "processing":
time.sleep(15)
job = requests.get(f"{API}/v1/transcripts/{job['id']}", headers=HEADERS).json()
print(job["text"][:500])