{"openapi":"3.0.0","info":{"title":"Pull That Up Jamie API","version":"1.0.0","description":"Public API for Pull That Up Jamie — a podcast search and research platform. Provides semantic search across podcast transcripts, corpus navigation for AI agents, research session management, and (upcoming) Lightning-based agent authentication.","contact":{"name":"Pull That Up Jamie","url":"https://pullthatupjamie.ai"},"license":{"name":"ISC"}},"servers":[{"url":"https://pullthatupjamie.ai","description":"Production"},{"url":"http://localhost:3000","description":"Local development"}],"tags":[{"name":"Corpus Discovery","description":"Read-only endpoints for navigating the podcast corpus hierarchy (feeds, episodes, chapters, topics, people). Designed for AI agents."},{"name":"Search","description":"Semantic search across podcast transcripts using vector embeddings."},{"name":"Discovery","description":"LLM-assisted podcast feed and episode search across 4M+ podcasts via the Podcast Index. Routes natural language queries to the best search backends for people, topics, and shows."},{"name":"On-Demand Transcription","description":"Submit podcast episodes for transcription, timestamped chaptering, keyword extraction, and permanent semantic indexing. Poll for job status and receive chapter data on completion. Once indexed, content is searchable via the Search endpoints."},{"name":"Research Sessions","description":"Create, retrieve, share, and analyze research sessions — curated collections of podcast clips."},{"name":"Create","description":"Generate shareable audio/video clips from podcast search results. Async processing with status polling."},{"name":"Agent Auth","description":"L402 Lightning-based prepaid credit system for agent API access. Hit any paid endpoint without auth to receive a 402 challenge with a Lightning invoice. After payment, use Authorization: L402 <macaroon>:<preimage> for all subsequent requests — the same credential works across all endpoints until the balance is depleted. Add ?amountSats=N to any request for a custom credit amount (min 10, max 500,000 sats). Each API call deducts its USD-equivalent cost from the prepaid balance. Compatible with lnget."},{"name":"Pull","description":"LLM-orchestrated agent endpoint. Send a natural-language research query and receive a Server-Sent Events (SSE) stream containing the agent's progress and a synthesized answer with podcast quotes, episode metadata, and optional follow-up actions. The agent can call internal tools (semantic quote search, chapter lookup, person resolution, podcast discovery) over multiple turns before delivering a final response. Authentication accepts L402 prepaid credentials, Bearer JWT, or anonymous free-tier quota (set X-Free-Tier: true to opt in). Per-tier quotas apply."}],"paths":{"/api/make-clip":{"post":{"tags":["Create"],"summary":"Create audio clip with burned-in subtitles","description":"Generates an MP4 video clip from a podcast segment with burned-in subtitles. Processing is asynchronous — poll /api/clip-status/{lookupHash} for completion. Clips are cached: identical clipId + timestamps return immediately at no extra cost. Agent pricing: $0.05/clip (50,000 microUSD). Free tier quotas: 5/week (anonymous), 10/month (registered), 50/month (subscriber). Typical processing: <1 min, max ~2 min.","parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"clipId":{"type":"string","example":"1015378_38c8e3a2b0e94b2b80feb2e426fbf0b3_p1234"},"timestamps":{"type":"array","example":[1234.5,1289],"items":{"type":"number"}}}},"description":"clipId (required): shareLink from a search result. timestamps (optional): [startSeconds, endSeconds] to override natural clip bounds."}],"responses":{"200":{"description":"Clip already exists (cached — no charge)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"lookupHash":{"type":"string","example":"abc123def456"},"url":{"type":"string","example":"https://cdn.pullthatupjamie.ai/clips/abc123.mp4"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"lookupHash":{"type":"string","example":"abc123def456"},"url":{"type":"string","example":"https://cdn.pullthatupjamie.ai/clips/abc123.mp4"}},"xml":{"name":"main"}}}}},"202":{"description":"Clip queued for processing — poll /api/clip-status/{lookupHash}","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"processing"},"lookupHash":{"type":"string","example":"abc123def456"},"pollUrl":{"type":"string","example":"/api/clip-status/abc123def456"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"processing"},"lookupHash":{"type":"string","example":"abc123def456"},"pollUrl":{"type":"string","example":"/api/clip-status/abc123def456"}},"xml":{"name":"main"}}}}},"400":{"description":"Missing required clipId parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"clipId is required"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"clipId is required"}},"xml":{"name":"main"}}}}},"404":{"description":"Clip ID not found in corpus","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Clip not found"},"clipId":{"type":"string","example":"1015378_invalid_p999"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Clip not found"},"clipId":{"type":"string","example":"1015378_invalid_p999"}},"xml":{"name":"main"}}}}},"429":{"description":"Quota exceeded or insufficient funds","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Quota exceeded"},"code":{"type":"string","example":"QUOTA_EXCEEDED"},"used":{"type":"number","example":10},"max":{"type":"number","example":10},"resetDate":{"type":"string","example":"2026-03-01T00:00:00Z"},"daysUntilReset":{"type":"number","example":5},"tier":{"type":"string","example":"registered"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Quota exceeded"},"code":{"type":"string","example":"QUOTA_EXCEEDED"},"used":{"type":"number","example":10},"max":{"type":"number","example":10},"resetDate":{"type":"string","example":"2026-03-01T00:00:00Z"},"daysUntilReset":{"type":"number","example":5},"tier":{"type":"string","example":"registered"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error during clip creation","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"}},"xml":{"name":"main"}}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"clipId":{"example":"any"},"timestamps":{"example":"any"}}}}}}}},"/api/clip-status/{lookupHash}":{"get":{"tags":["Create"],"summary":"Check audio clip processing status","description":"Poll this endpoint to check if a clip has finished processing. No authentication required — the lookupHash serves as the credential. Recommended polling: every 5 seconds, max 30 attempts (~2.5 min timeout).","parameters":[{"name":"lookupHash","in":"path","required":true,"schema":{"type":"string"},"description":"The lookupHash returned from POST /api/make-clip"}],"responses":{"200":{"description":"Clip status (completed, processing, or failed)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"url":{"type":"string","example":"https://cdn.pullthatupjamie.ai/clips/abc123.mp4"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"completed"},"url":{"type":"string","example":"https://cdn.pullthatupjamie.ai/clips/abc123.mp4"}},"xml":{"name":"main"}}}}},"404":{"description":"Lookup hash not found","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"not_found"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"not_found"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"}},"xml":{"name":"main"}}}}}}}},"/api/search-quotes":{"post":{"tags":["Search"],"summary":"Semantic search across podcast transcripts","description":"Performs vector-based semantic search across the podcast corpus using OpenAI embeddings and Pinecone. Supports filtering by feed, episode, date range, and episode name.","parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"query":{"type":"string","example":"What is the future of Bitcoin?"},"feedIds":{"type":"array","example":["1015378"],"items":{"type":"string"}},"limit":{"type":"number","example":5},"minDate":{"type":"string","example":"2024-01-01"},"maxDate":{"type":"string","example":"2026-02-13"},"episodeName":{"type":"string","example":""},"guid":{"type":"string","example":""}}}}],"responses":{"200":{"description":"Search results with similarity scores","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","example":"What is the future of Bitcoin?"},"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"total":{"type":"number","example":5},"model":{"type":"string","example":"text-embedding-ada-002"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"query":{"type":"string","example":"What is the future of Bitcoin?"},"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"total":{"type":"number","example":5},"model":{"type":"string","example":"text-embedding-ada-002"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Failed to search quotes"},"details":{"type":"string","example":"Error message"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Failed to search quotes"},"details":{"type":"string","example":"Error message"}},"xml":{"name":"main"}}}}}}}},"/api/search-chapters":{"post":{"tags":["Search"],"summary":"Search chapters across the podcast corpus","description":"Searches chapter metadata (keywords, headline, summary) across the entire corpus. Returns matching chapters with parent episode context. L402 payment required.","parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"search":{"type":"string","example":"Lightning Network"},"feedIds":{"type":"array","example":["1015378"],"items":{"type":"string"}},"limit":{"type":"number","example":20},"page":{"type":"number","example":1}}}}],"responses":{"200":{"description":"Paginated chapter search results with episode context","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"chapter":{"$ref":"#/components/schemas/Chapter"},"episode":{"type":"object","properties":{"guid":{"type":"string","example":"abc123"},"title":{"type":"string","example":"Bitcoin Scaling Solutions"},"creator":{"type":"string","example":"Peter McCormack"},"publishedDate":{"type":"string","example":"2026-01-15"},"feedId":{"type":"string","example":"123456"},"imageUrl":{"type":"string","example":"https://..."},"listenLink":{"type":"string","example":"https://..."}}}}}},"pagination":{"$ref":"#/components/schemas/Pagination"},"query":{"type":"object","properties":{"search":{"type":"string","example":"Lightning Network"},"feedIds":{"type":"array","example":["1015378"],"items":{"type":"string"}}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"chapter":{"$ref":"#/components/schemas/Chapter"},"episode":{"type":"object","properties":{"guid":{"type":"string","example":"abc123"},"title":{"type":"string","example":"Bitcoin Scaling Solutions"},"creator":{"type":"string","example":"Peter McCormack"},"publishedDate":{"type":"string","example":"2026-01-15"},"feedId":{"type":"string","example":"123456"},"imageUrl":{"type":"string","example":"https://..."},"listenLink":{"type":"string","example":"https://..."}}}}}},"pagination":{"$ref":"#/components/schemas/Pagination"},"query":{"type":"object","properties":{"search":{"type":"string","example":"Lightning Network"},"feedIds":{"type":"array","example":["1015378"],"items":{"type":"string"}}}}},"xml":{"name":"main"}}}}},"400":{"description":"Missing search parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Bad request"},"message":{"type":"string","example":"search is required in request body"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Bad request"},"message":{"type":"string","example":"search is required in request body"}},"xml":{"name":"main"}}}}},"402":{"description":"Payment required (L402)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/L402Challenge"}},"application/xml":{"schema":{"$ref":"#/components/schemas/L402Challenge"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/pull":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery, research-session assembly) across one or more rounds, then composes a final answer with quoted passages and episode metadata. MODEL ROUTING: Optional `model` field accepts `quality` (default — DeepSeek V4-Flash, recommended for nearly all callers) or `fast` (Haiku 4.5, lower-cost). Omit for the default. RESPONSE MODE: Defaults to a single JSON body (`{ sessionId, text, suggestedActions, session? }`) after the full agent loop completes. To opt into live streaming, either set `stream: true` in the request body OR send `Accept: text/event-stream`. In streaming mode the response is an SSE connection with event types: `status` (progress updates), `tool_call` (`{ tool, input, round }`), `tool_result` (`{ tool, resultCount, latencyMs, round, meta? }` — optional `meta` carries lexical/vector breakdown for `search_quotes`), `session_created` (`{ sessionId, url, itemCount }` when the agent assembles a research session), `suggested_action` (next-step chip), `text_delta` (incremental answer chunk), `text_done` (authoritative final text), `done` (terminal envelope with rounds, tokens, cost, latency), and `error` (mid-stream failure). See the SSE schema example below for full payload shapes. PRICING: $0.10 per call, deducted from the prepaid L402 balance. AUTH: accepts L402 credentials, Bearer JWT, or anonymous free-tier quota (set X-Free-Tier: true). INVOICE AMOUNT: if you call without credentials to receive a 402 challenge, the invoice is auto-sized to cover approximately one call at the current BTC/USD rate (cost + ~2% buffer). Pass `?amountSats=N` (min 10, max 500,000) to prefund multiple calls. STATELESS CLIENT FLOW: the default invoice size means you can safely pay once, make one call, and discard the macaroon — no credential management required. Replaying the URL with `?amountSats` on the retry is harmless (the query param is silently ignored when a valid credential is present; the existing balance is debited).","parameters":[{"name":"amountSats","in":"query","required":false,"minimum":10,"maximum":500000,"description":"Optional. Specifies the sats amount for the returned Lightning invoice when calling without an L402 credential (to receive a 402 challenge). When omitted, the invoice is auto-sized to cover approximately one call at the current BTC/USD rate (cost + ~2% buffer). Use this to prefund multiple calls or to purchase bulk credits. Silently ignored when an Authorization: L402 header is already present — the existing balance is debited instead.","schema":{"type":"integer"}},{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"message":{"type":"string","example":"What did Luke Gromen say about debt deflation this month?"},"model":{"type":"string","enum":["quality","fast"],"default":"quality","description":"Optional routing hint. `quality` (default) is the production path — currently DeepSeek V4-Flash, recommended for nearly all use cases including multi-step research, person/episode resolution, and research-session curation. `fast` falls through to a smaller helper model (Haiku 4.5) for budget-sensitive or latency-tight callers; expect lower fidelity on multi-step tasks. If omitted, `quality` is used. Internal model keys (e.g. `deepseek-v4-flash-direct`, `sonnet-4-6`) are accepted but not part of the public contract — pass `quality` or `fast` for stable behavior.","example":"quality"},"sessionId":{"type":"string","example":"optional-agent-session-id"},"stream":{"type":"boolean","example":false},"history":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","example":"assistant"},"content":{"type":"string","example":"previous assistant turn"}}}},"context":{"type":"object","properties":{"guids":{"type":"array","example":["episode-guid-1"],"items":{"type":"string"}},"feedIds":{"type":"array","example":["1015378"],"items":{"type":"string"}},"persons":{"type":"array","example":["Luke Gromen"],"items":{"type":"string"}},"hint":{"type":"string","example":"focus on recent inflation commentary"}}}}},"description":"Only the message field is required. model defaults to `quality` (DeepSeek V4-Flash) — pass `fast` for the cheaper Haiku-backed path. stream defaults to false (single JSON response once the agent finishes); set true or send Accept: text/event-stream to receive an SSE stream of intermediate events. sessionId enables multi-turn continuity (auto-generated if omitted). history supplies prior turns (most recent last, each entry is role + content). context is optional pre-resolved hints from a prior suggested follow-up action."}],"responses":{"200":{"description":"Agent response. Default (stream=false): single application/json body with { sessionId, text, suggestedActions, session? } after the full agent loop completes (session is populated only when the agent built a research session). Streaming mode (stream=true OR Accept: text/event-stream): text/event-stream connection with incremental events (status, tool_call, tool_result, session_created, suggested_action, text_delta, text_done, done, error).","content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","example":"agent-1234567890-abc123"},"text":{"type":"string","description":"Final synthesized answer. May contain {{clip:shareLink}} placeholders that clients can render as inline quote cards.","example":"Luke Gromen argued the debt deflation dynamic..."},"suggestedActions":{"type":"array","description":"Optional follow-up chips and/or transcription-card offers. Discriminated union on `type`. `submit-on-demand` offers transcription of an untranscribed episode (carries `feedId`, `guid`, `feedGuid`, `episodeTitle`, `image`, `enclosureUrl`, `link`, `reason`). `follow-up-message` is a one-click pre-filled chat message (carries `label`, `message`, optional `context: { guids, feedIds, persons, hint }`, `reason`). `create-clip` is reserved for a future skill. Treat unknown `type` values as no-ops so older clients keep working as new variants ship.","items":{"type":"object","properties":{"type":{"type":"string","enum":["submit-on-demand","follow-up-message","create-clip"]},"label":{"type":"string","description":"Short user-facing chip text (used by `follow-up-message`). Prefer this over `message` for display; never render `reason` as a label."},"message":{"type":"string","description":"Pre-filled chat message body for `follow-up-message`. POST this back to /api/pull as the next turn's `message` (along with `context` if present). Truncate for display; use `label` instead."},"reason":{"type":"string","description":"Internal-ish explanation the agent emits for debuggability — not user-facing copy."},"context":{"type":"object","description":"Pre-resolved hints to pass back unchanged on the follow-up turn so the next agent run skips re-resolving entities.","properties":{"guids":{"type":"array","items":{"type":"string"}},"feedIds":{"type":"array","items":{"type":"string"}},"persons":{"type":"array","items":{"type":"string"}},"hint":{"type":"string"}}},"feedId":{"type":"string","description":"submit-on-demand only."},"guid":{"type":"string","description":"submit-on-demand only."},"feedGuid":{"type":"string","description":"submit-on-demand only."},"episodeTitle":{"type":"string","description":"submit-on-demand only."},"image":{"type":"string","description":"submit-on-demand only."},"enclosureUrl":{"type":"string","description":"submit-on-demand only."},"link":{"type":"string","description":"submit-on-demand only."}}}},"session":{"type":"object","nullable":true,"description":"Populated only if the agent created a shareable research session.","properties":{"sessionId":{"type":"string"},"url":{"type":"string"},"itemCount":{"type":"integer"}}}}}},"text/event-stream":{"schema":{"type":"string","description":"SSE event stream. Each frame is `event: <type>\\ndata: <json>\\n\\n`. Event types: `status` (human-readable progress string), `tool_call` (agent invoked a tool: `{ tool, input, round }`), `tool_result` (tool returned: `{ tool, resultCount, latencyMs, round, meta? }` — `meta` is currently populated only for `search_quotes` and carries `{ lexical, vector, mix, expansion, reranker, ... }` for the lexical-vs-semantic breakdown), `session_created` (the agent assembled a research session: `{ sessionId, url, itemCount }`), `suggested_action` (proactive next-step chip — see suggestedActions[] schema in the JSON response), `text_delta` (incremental answer chunk: `{ text }`), `text_done` (authoritative final text: `{ text }`), `done` (terminal envelope — see fields below), `error` (mid-stream failure: `{ error }`). The terminal `done` payload shape is `{ sessionId, provider, model, modelKey, executionProfile, intent, rounds, toolCalls: [{ name, resultCount, latencyMs }], tokens: { input, output }, cost: { claude, tools, total }, latencyMs, naturalCompletion, synthesisExitReason }`. Note on `cost`: field names are retained for backward compatibility — `cost.claude` is the orchestrator-LLM marginal spend (currently DeepSeek when `model=quality`, Haiku when `model=fast`); `cost.tools` is always `0` by design (per-tool flat-fee tracking was removed in the 2026-04 cost-tracker refactor; helper-LLM spend rolls into `cost.total`). Treat unknown event types as no-ops and keep reading.","example":"event: status\ndata: {\"message\":\"Analyzing your request...\",\"sessionId\":\"agent-1234...\"}\n\nevent: tool_call\ndata: {\"tool\":\"search_quotes\",\"input\":{\"query\":\"debt deflation\"},\"round\":1}\n\nevent: tool_result\ndata: {\"tool\":\"search_quotes\",\"resultCount\":12,\"latencyMs\":812,\"round\":1,\"meta\":{\"lexical\":{\"hits\":4,\"latencyMs\":120},\"vector\":{\"hits\":10,\"latencyMs\":180},\"mix\":\"hybrid\",\"expansion\":{\"variants\":[\"debt deflation\",\"debt-deflation cycle\"]},\"reranker\":{\"input\":14,\"kept\":12,\"removed\":2}}}\n\nevent: text_delta\ndata: {\"text\":\"Luke Gromen argued...\"}\n\nevent: session_created\ndata: {\"sessionId\":\"abc123\",\"url\":\"https://www.pullthatupjamie.ai/app?researchSessionId=abc123\",\"itemCount\":7}\n\nevent: text_done\ndata: {\"text\":\"Luke Gromen argued the debt deflation dynamic...\"}\n\nevent: done\ndata: {\"sessionId\":\"agent-1234...\",\"provider\":\"deepseek\",\"model\":\"DeepSeek V4-Flash (Direct)\",\"modelKey\":\"quality\",\"executionProfile\":\"default\",\"intent\":\"research_session\",\"rounds\":3,\"toolCalls\":[{\"name\":\"search_quotes\",\"resultCount\":12,\"latencyMs\":812}],\"tokens\":{\"input\":4120,\"output\":880},\"cost\":{\"claude\":0.0081,\"tools\":0,\"total\":0.0093},\"latencyMs\":5240,\"naturalCompletion\":true,\"synthesisExitReason\":\"primary\"}\n\n"}}}},"400":{"description":"Missing or invalid `message` in request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"message (or task) is required"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"message (or task) is required"}},"xml":{"name":"main"}}}}},"402":{"description":"Payment Required. Returned when an anonymous caller hits the endpoint without opting into free-tier (no `X-Free-Tier: true` header) OR when free-tier quota is exhausted and the caller is anonymous. Includes an L402 challenge in the WWW-Authenticate header with a Lightning invoice. Pay the invoice and retry with Authorization: L402 <macaroon>:<preimage>.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Payment required"},"code":{"type":"string","example":"PAYMENT_REQUIRED"},"invoice":{"type":"string","example":"lnbc..."},"macaroon":{"type":"string","example":"base64..."}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Payment required"},"code":{"type":"string","example":"PAYMENT_REQUIRED"},"invoice":{"type":"string","example":"lnbc..."},"macaroon":{"type":"string","example":"base64..."}},"xml":{"name":"main"}}}}},"429":{"description":"Quota exceeded for the caller's tier. Wait until `resetDate` or upgrade to a higher tier (subscriber / L402 prepaid).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Quota exceeded"},"code":{"type":"string","example":"QUOTA_EXCEEDED"},"used":{"type":"number","example":10},"max":{"type":"number","example":10},"resetDate":{"type":"string","example":"2026-05-20T00:00:00.000Z"},"daysUntilReset":{"type":"number","example":23},"tier":{"type":"string","example":"registered"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Quota exceeded"},"code":{"type":"string","example":"QUOTA_EXCEEDED"},"used":{"type":"number","example":10},"max":{"type":"number","example":10},"resetDate":{"type":"string","example":"2026-05-20T00:00:00.000Z"},"daysUntilReset":{"type":"number","example":23},"tier":{"type":"string","example":"registered"}},"xml":{"name":"main"}}}}},"503":{"description":"Agent backend is not configured (missing or invalid API key for the active provider). The active provider is determined by the `model` parameter — `quality` (default) requires DEEPSEEK_API_KEY; `fast` requires ANTHROPIC_API_KEY. The error message names the offending env var.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"deepseek provider is not configured or unavailable. Check DEEPSEEK_API_KEY in .env"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"deepseek provider is not configured or unavailable. Check DEEPSEEK_API_KEY in .env"}},"xml":{"name":"main"}}}}}},"security":[{"L402Credential":[]},{"BearerJWT":[]},{}]}},"/api/on-demand/submitOnDemandRun":{"post":{"tags":["On-Demand Transcription"],"summary":"Submit a podcast episode for transcription, chaptering, and semantic indexing","description":"Submits a podcast episode for full transcription, timestamped chaptering, keyword extraction, and permanent semantic indexing. Returns a pollable job status URL. Once indexed, content is searchable via /api/search-quotes. L402 prepaid access limited to 1 episode per request. Use /api/discover-podcasts to find episode GUIDs.\\n\\nA metered free tier is available: send the header `X-Free-Tier: true` to use quota-based access without payment. Anonymous users get 2 transcriptions per week; registered users get 5 per month. Omit the header (or use L402 credentials) for paid access.","parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"message":{"type":"string","example":"Transcribe latest episode from Bankless"},"parameters":{"type":"object","properties":{}},"episodes":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string","example":"dd043afd-d7f8-4a96-97aa-a24a743fc219"},"feedGuid":{"type":"string","example":"3d510171-b9ab-517c-bbf3-1fd5542479ad"},"feedId":{"type":"string","example":"357756"}}}}}}}],"responses":{"200":{"description":"Job submitted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"},"totalEpisodes":{"type":"number","example":1},"totalFeeds":{"type":"number","example":1},"message":{"type":"string","example":"On-demand run submitted successfully"},"nextSteps":{"type":"object","properties":{"pollJobStatus":{"type":"object","properties":{"description":{"type":"string","example":"Poll until status is \"complete\". Typical transcription takes 30-120 seconds per episode."},"method":{"type":"string","example":"POST"},"url":{"type":"string","example":"/api/on-demand/getOnDemandJobStatus"},"body":{"type":"object","properties":{"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"}}},"pollIntervalSeconds":{"type":"number","example":15}}},"searchTranscripts":{"type":"object","properties":{"description":{"type":"string","example":"Once job is complete, search the transcribed content with semantic queries"},"method":{"type":"string","example":"POST"},"url":{"type":"string","example":"/api/search-quotes"},"body":{"type":"object","properties":{"query":{"type":"string","example":"..."},"feedIds":{"type":"array","example":["357756"],"items":{"type":"string"}},"smartMode":{"type":"boolean","example":true}}}}}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"},"totalEpisodes":{"type":"number","example":1},"totalFeeds":{"type":"number","example":1},"message":{"type":"string","example":"On-demand run submitted successfully"},"nextSteps":{"type":"object","properties":{"pollJobStatus":{"type":"object","properties":{"description":{"type":"string","example":"Poll until status is \"complete\". Typical transcription takes 30-120 seconds per episode."},"method":{"type":"string","example":"POST"},"url":{"type":"string","example":"/api/on-demand/getOnDemandJobStatus"},"body":{"type":"object","properties":{"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"}}},"pollIntervalSeconds":{"type":"number","example":15}}},"searchTranscripts":{"type":"object","properties":{"description":{"type":"string","example":"Once job is complete, search the transcribed content with semantic queries"},"method":{"type":"string","example":"POST"},"url":{"type":"string","example":"/api/search-quotes"},"body":{"type":"object","properties":{"query":{"type":"string","example":"..."},"feedIds":{"type":"array","example":["357756"],"items":{"type":"string"}},"smartMode":{"type":"boolean","example":true}}}}}}}},"xml":{"name":"main"}}}}},"400":{"description":"Validation error or L402 batch limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required — returns Lightning invoice"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"example":"any"},"parameters":{"example":"any"},"episodes":{"example":"any"}}}}}}}},"/api/on-demand/getOnDemandJobStatus":{"post":{"tags":["On-Demand Transcription"],"summary":"Get transcription job status with chapters on completion","description":"Returns job status and per-episode progress. When status is \"complete\", the response is enriched with chapter headlines, keywords, summaries, and timestamps for each successfully transcribed episode, plus a nextSteps block pointing to /api/search-quotes for semantic search across the newly indexed content. No authentication required for basic polling — anyone with the jobId can poll.\\n\\nOptional: if the caller includes an Authorization header with the same L402 credential used to pay for the job, each completed episode will also include a `transcriptUrl` — a relative path to GET /api/on-demand/transcript/{jobId}/{guid} that streams the full transcript JSON through an authenticated proxy. The same L402 credential must be presented to that endpoint.","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"}}}},{"name":"Authorization","in":"header","required":false,"description":"Optional L402 credential (L402 <macaroon>:<preimage>). When present and matching the credential that paid for the job, transcript download URLs are included.","schema":{"type":"string"}}],"responses":{"200":{"description":"Job status with optional chapter enrichment and transcript URLs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"},"status":{"type":"string","example":"complete"},"stats":{"type":"object","properties":{"totalEpisodes":{"type":"number","example":1},"totalFeeds":{"type":"number","example":1},"episodesProcessed":{"type":"number","example":1},"episodesSkipped":{"type":"number","example":0},"episodesFailed":{"type":"number","example":0}}},"episodes":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string","example":"dd043afd-d7f8-4a96-97aa-a24a743fc219"},"feedId":{"type":"string","example":"357756"},"status":{"type":"string","example":"success"},"chapters":{"type":"array","items":{"type":"object","properties":{"chapterNumber":{"type":"number","example":1},"headline":{"type":"string","example":"SEC and CFTC Developments in Crypto"},"keywords":{"type":"array","example":["SEC","CFTC","crypto regulations"],"items":{"type":"string"}},"summary":{"type":"string","example":"Discussion on SEC and CFTC actions regarding crypto..."},"startTime":{"type":"number","example":0},"endTime":{"type":"number","example":159.48}}}},"transcriptUrl":{"type":"string","example":"/api/on-demand/transcript/6b2440adae3f806198eb56c0/dd043afd-d7f8-4a96-97aa-a24a743fc219"}}}},"nextSteps":{"type":"object","properties":{"downloadTranscript":{"type":"object","properties":{"description":{"type":"string","example":"Download the full transcript JSON for each completed episode. Requires the same L402 credential that paid for the job. The transcriptUrl for each episode is included above when a valid L402 credential is presented."},"method":{"type":"string","example":"GET"},"url":{"type":"string","example":"/api/on-demand/transcript/{jobId}/{guid}"},"headers":{"type":"object","properties":{"Authorization":{"type":"string","example":"L402 <macaroon>:<preimage>"}}}}},"searchTranscripts":{"type":"object","properties":{"description":{"type":"string","example":"Semantic search across the newly transcribed content with timestamped deeplinks"},"method":{"type":"string","example":"POST"},"url":{"type":"string","example":"/api/search-quotes"},"body":{"type":"object","properties":{"query":{"type":"string","example":"..."},"feedIds":{"type":"array","example":["357756"],"items":{"type":"string"}},"smartMode":{"type":"boolean","example":true}}}}}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"jobId":{"type":"string","example":"6b2440adae3f806198eb56c0"},"status":{"type":"string","example":"complete"},"stats":{"type":"object","properties":{"totalEpisodes":{"type":"number","example":1},"totalFeeds":{"type":"number","example":1},"episodesProcessed":{"type":"number","example":1},"episodesSkipped":{"type":"number","example":0},"episodesFailed":{"type":"number","example":0}}},"episodes":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string","example":"dd043afd-d7f8-4a96-97aa-a24a743fc219"},"feedId":{"type":"string","example":"357756"},"status":{"type":"string","example":"success"},"chapters":{"type":"array","items":{"type":"object","properties":{"chapterNumber":{"type":"number","example":1},"headline":{"type":"string","example":"SEC and CFTC Developments in Crypto"},"keywords":{"type":"array","example":["SEC","CFTC","crypto regulations"],"items":{"type":"string"}},"summary":{"type":"string","example":"Discussion on SEC and CFTC actions regarding crypto..."},"startTime":{"type":"number","example":0},"endTime":{"type":"number","example":159.48}}}},"transcriptUrl":{"type":"string","example":"/api/on-demand/transcript/6b2440adae3f806198eb56c0/dd043afd-d7f8-4a96-97aa-a24a743fc219"}}}},"nextSteps":{"type":"object","properties":{"downloadTranscript":{"type":"object","properties":{"description":{"type":"string","example":"Download the full transcript JSON for each completed episode. Requires the same L402 credential that paid for the job. The transcriptUrl for each episode is included above when a valid L402 credential is presented."},"method":{"type":"string","example":"GET"},"url":{"type":"string","example":"/api/on-demand/transcript/{jobId}/{guid}"},"headers":{"type":"object","properties":{"Authorization":{"type":"string","example":"L402 <macaroon>:<preimage>"}}}}},"searchTranscripts":{"type":"object","properties":{"description":{"type":"string","example":"Semantic search across the newly transcribed content with timestamped deeplinks"},"method":{"type":"string","example":"POST"},"url":{"type":"string","example":"/api/search-quotes"},"body":{"type":"object","properties":{"query":{"type":"string","example":"..."},"feedIds":{"type":"array","example":["357756"],"items":{"type":"string"}},"smartMode":{"type":"boolean","example":true}}}}}}}},"xml":{"name":"main"}}}}},"400":{"description":"Bad Request"},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"jobId":{"example":"any"}}}}}}}},"/api/on-demand/transcript/{jobId}/{guid}":{"get":{"tags":["On-Demand Transcription"],"summary":"Download full transcript JSON for a transcribed episode","description":"Streams the full transcript JSON for the given episode. Requires the same L402 credential that was used to pay for the transcription job.","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"Job ID returned by submitOnDemandRun"},{"name":"guid","in":"path","required":true,"schema":{"type":"string"},"description":"Episode GUID"},{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"Authorization","in":"header","required":true,"description":"L402 credential (L402 <macaroon>:<preimage>) matching the one that paid for the job","schema":{"type":"string"}}],"responses":{"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"},"502":{"description":"Bad Gateway"},"503":{"description":"Service Unavailable"},"504":{"description":"Gateway Timeout"}}}},"/api/research-sessions/":{"post":{"tags":["Research Sessions"],"summary":"Create a new research session","description":"Creates a new research session with an ordered list of Pinecone vector IDs. Requires either a Bearer JWT or a clientId for ownership.","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"x-client-id","in":"header","schema":{"type":"string"}},{"name":"req","in":"query","schema":{"type":"string"}},{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"clientId":{"type":"string","example":"optional-when-authenticated"},"pineconeIds":{"type":"array","example":["id1","id2","id3"],"items":{"type":"string"}},"lastItemMetadata":{"type":"object","properties":{}},"coordinatesById":{"type":"object","properties":{}}}}}],"responses":{"201":{"description":"Research session created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","example":"507f1f77bcf86cd799439011"},"pineconeIds":{"type":"array","example":["id1","id2","id3"],"items":{"type":"string"}},"createdAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","example":"507f1f77bcf86cd799439011"},"pineconeIds":{"type":"array","example":["id1","id2","id3"],"items":{"type":"string"}},"createdAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}}}},"xml":{"name":"main"}}}}},"400":{"description":"Invalid request (missing owner or invalid pineconeIds)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid pineconeIds"},"details":{"type":"string","example":"pineconeIds must be a non-empty array of strings"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid pineconeIds"},"details":{"type":"string","example":"pineconeIds must be a non-empty array of strings"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error creating research session"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error creating research session"}},"xml":{"name":"main"}}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"example":"any"},"pineconeIds":{"example":"any"},"lastItemMetadata":{"example":"any"},"coordinatesById":{"example":"any"},"req":{"example":"any"}}}}}}}},"/api/research-sessions/{id}":{"get":{"tags":["Research Sessions"],"summary":"Get a research session by ID","description":"Returns a specific research session with all its items and metadata. Hydrates item data from MongoDB and Pinecone as needed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Research session ID (MongoDB ObjectId)"},{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"x-client-id","in":"header","schema":{"type":"string"}},{"name":"req","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Research session with items","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"session":{"type":"object","properties":{"_id":{"type":"string","example":"507f1f77bcf86cd799439011"},"pineconeIds":{"type":"array","example":["id1","id2"],"items":{"type":"string"}},"lastItemMetadata":{"type":"object","properties":{}},"createdAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}}},"items":{"type":"array","example":[],"items":{}}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"session":{"type":"object","properties":{"_id":{"type":"string","example":"507f1f77bcf86cd799439011"},"pineconeIds":{"type":"array","example":["id1","id2"],"items":{"type":"string"}},"lastItemMetadata":{"type":"object","properties":{}},"createdAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}}},"items":{"type":"array","example":[],"items":{}}}}},"xml":{"name":"main"}}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Research session not found"},"details":{"type":"string","example":"No session found for this id"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Research session not found"},"details":{"type":"string","example":"No session found for this id"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error fetching research session"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error fetching research session"}},"xml":{"name":"main"}}}}}}}},"/api/research-sessions/{id}/share":{"post":{"tags":["Research Sessions"],"summary":"Create a shareable snapshot of a session","description":"Creates an immutable, shareable snapshot of a research session with a preview image. When nodes is omitted the backend auto-generates a 3D layout from stored session coordinates (useful for headless/agent callers).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Research session ID (MongoDB ObjectId)"},{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"title":{"type":"string","example":"My Research on Bitcoin"},"nodes":{"type":"array","items":{"type":"object","properties":{"pineconeId":{"type":"string","example":"id1"},"x":{"type":"number","example":0},"y":{"type":"number","example":0},"z":{"type":"number","example":0},"color":{"type":"string","example":"#4a9eff"}}}},"camera":{"type":"object","properties":{"x":{"type":"number","example":0},"y":{"type":"number","example":0},"z":{"type":"number","example":5}}},"visibility":{"type":"string","example":"unlisted"}}},"description":"nodes is optional. When omitted the server generates a layout from the session items stored coordinates."},{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"x-client-id","in":"header","schema":{"type":"string"}},{"name":"req","in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":"Shared session created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"shareId":{"type":"string","example":"8d5417e36d3d"},"shareUrl":{"type":"string","example":"https://pullthatupjamie.ai/researchSession/8d5417e36d3d"},"previewImageUrl":{"type":"string","example":"https://..."},"generatedLayout":{"type":"boolean","example":false}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"shareId":{"type":"string","example":"8d5417e36d3d"},"shareUrl":{"type":"string","example":"https://pullthatupjamie.ai/researchSession/8d5417e36d3d"},"previewImageUrl":{"type":"string","example":"https://..."},"generatedLayout":{"type":"boolean","example":false}}}},"xml":{"name":"main"}}}}},"400":{"description":"Invalid snapshot or missing owner","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid snapshot"},"details":{"type":"string","example":"Validation error message"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid snapshot"},"details":{"type":"string","example":"Validation error message"}},"xml":{"name":"main"}}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Research session not found"},"details":{"type":"string","example":"No session found for this id and owner"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Research session not found"},"details":{"type":"string","example":"No session found for this id and owner"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error sharing research session"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error sharing research session"}},"xml":{"name":"main"}}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"in":{"example":"any"},"required":{"example":"any"},"schema":{"example":"any"},"camera":{"example":"any"},"visibility":{"example":"any"},"req":{"example":"any"}}}}}}}},"/api/research-sessions/{id}/analyze":{"post":{"tags":["Research Sessions"],"summary":"Analyze a research session with AI","description":"Analyzes a research session using gpt-4o-mini and streams the response as Server-Sent Events (SSE). Optionally provide custom instructions to guide the analysis.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Research session ID (MongoDB ObjectId)"},{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"x-client-id","in":"header","schema":{"type":"string"}},{"name":"req","in":"query","schema":{"type":"string"}},{"name":"body","in":"body","required":false,"schema":{"type":"object","properties":{"instructions":{"type":"string","example":"Summarize the key themes discussed across these clips"}}}}],"responses":{"200":{"description":"SSE stream of analysis text","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"description":"Empty session or missing owner","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Empty session"},"details":{"type":"string","example":"This research session has no items to analyze"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Empty session"},"details":{"type":"string","example":"This research session has no items to analyze"}},"xml":{"name":"main"}}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Research session not found"},"details":{"type":"string","example":"No session found for this id"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Research session not found"},"details":{"type":"string","example":"No session found for this id"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error analyzing research session with AI"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error analyzing research session with AI"}},"xml":{"name":"main"}}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"instructions":{"example":"any"},"req":{"example":"any"}}}}}}}},"/api/shared-research-sessions/{shareId}":{"get":{"tags":["Research Sessions"],"summary":"Get a shared research session","description":"Returns metadata for a shared research session by its shareId. Intended for link unfurling and preview cards. Includes title, description, preview image, node positions, and camera configuration.","parameters":[{"name":"shareId","in":"path","required":true,"schema":{"type":"string"},"description":"Shared session identifier (12-character hex string)"}],"responses":{"200":{"description":"Shared session metadata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"researchSessionId":{"type":"string","example":"507f1f77bcf86cd799439011"},"shareId":{"type":"string","example":"8d5417e36d3d"},"shareUrl":{"type":"string","example":"https://pullthatupjamie.ai/researchSession/8d5417e36d3d"},"title":{"type":"string","example":"My Research on Bitcoin"},"brandImage":{},"brandColors":{"type":"array","example":[],"items":{}},"description":{"type":"string","example":"Short description or quote..."},"previewImageUrl":{"type":"string","example":"https://.../preview.jpg"},"visibility":{"type":"string","example":"unlisted"},"lastItemMetadata":{"type":"object","properties":{}},"nodes":{"type":"array","example":[],"items":{}},"camera":{"type":"object","properties":{}},"createdAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"researchSessionId":{"type":"string","example":"507f1f77bcf86cd799439011"},"shareId":{"type":"string","example":"8d5417e36d3d"},"shareUrl":{"type":"string","example":"https://pullthatupjamie.ai/researchSession/8d5417e36d3d"},"title":{"type":"string","example":"My Research on Bitcoin"},"brandImage":{},"brandColors":{"type":"array","example":[],"items":{}},"description":{"type":"string","example":"Short description or quote..."},"previewImageUrl":{"type":"string","example":"https://.../preview.jpg"},"visibility":{"type":"string","example":"unlisted"},"lastItemMetadata":{"type":"object","properties":{}},"nodes":{"type":"array","example":[],"items":{}},"camera":{"type":"object","properties":{}},"createdAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}}}},"xml":{"name":"main"}}}}},"400":{"description":"Invalid shareId","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid shareId"},"details":{"type":"string","example":"shareId path parameter is required"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid shareId"},"details":{"type":"string","example":"shareId path parameter is required"}},"xml":{"name":"main"}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"},"details":{"type":"string","example":"No shared research session found for this shareId"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"},"details":{"type":"string","example":"No shared research session found for this shareId"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error fetching shared research session metadata"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"details":{"type":"string","example":"Error fetching shared research session metadata"}},"xml":{"name":"main"}}}}}}}},"/api/corpus/spec":{"get":{"tags":["Corpus Discovery"],"summary":"Get API specification as markdown","description":"Returns the Corpus API specification as a markdown document. Useful for agents to understand available endpoints.","responses":{"200":{"description":"Markdown API specification","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/api/corpus/stats":{"get":{"tags":["Corpus Discovery"],"summary":"Get corpus-wide statistics","description":"Returns aggregate counts for feeds, episodes, chapters, paragraphs, people, and topics across the entire corpus.","responses":{"200":{"description":"Corpus statistics","content":{"application/json":{"schema":{"type":"object","properties":{"feeds":{"type":"object","properties":{"total":{"type":"number","example":10}}},"episodes":{"type":"object","properties":{"total":{"type":"number","example":5000}}},"chapters":{"type":"object","properties":{"total":{"type":"number","example":50000}}},"paragraphs":{"type":"object","properties":{"total":{"type":"number","example":500000}}},"people":{"type":"object","properties":{"creators":{"type":"number","example":10},"guests":{"type":"number","example":500},"total":{"type":"number","example":510}}},"topics":{"type":"object","properties":{"total":{"type":"number","example":2000}}},"generatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"feeds":{"type":"object","properties":{"total":{"type":"number","example":10}}},"episodes":{"type":"object","properties":{"total":{"type":"number","example":5000}}},"chapters":{"type":"object","properties":{"total":{"type":"number","example":50000}}},"paragraphs":{"type":"object","properties":{"total":{"type":"number","example":500000}}},"people":{"type":"object","properties":{"creators":{"type":"number","example":10},"guests":{"type":"number","example":500},"total":{"type":"number","example":510}}},"topics":{"type":"object","properties":{"total":{"type":"number","example":2000}}},"generatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/feeds":{"get":{"tags":["Corpus Discovery"],"summary":"List all podcast feeds","description":"Returns a paginated list of all podcast feeds in the corpus.","parameters":[{"name":"limit","in":"query","description":"Results per page (default: 50, max: 200)","required":false,"schema":{"type":"integer"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated feed list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Feed"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Feed"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/feeds/{feedId}/stats":{"get":{"tags":["Corpus Discovery"],"summary":"Get statistics for a specific feed","description":"Returns episode, chapter, and paragraph counts plus date range for a specific feed. Useful for agents to assess feed depth before searching.","parameters":[{"name":"feedId","in":"path","required":true,"schema":{"type":"string"},"description":"Feed identifier"}],"responses":{"200":{"description":"Feed statistics","content":{"application/json":{"schema":{"type":"object","properties":{"feedId":{"type":"string","example":"1015378"},"title":{"type":"string","example":"What Bitcoin Did"},"episodeCount":{"type":"number","example":824},"chapterCount":{"type":"number","example":3200},"paragraphCount":{"type":"number","example":45000},"dateRange":{"type":"object","properties":{"earliest":{"type":"string","example":"2018-11-01"},"latest":{"type":"string","example":"2026-02-06"}}},"generatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"feedId":{"type":"string","example":"1015378"},"title":{"type":"string","example":"What Bitcoin Did"},"episodeCount":{"type":"number","example":824},"chapterCount":{"type":"number","example":3200},"paragraphCount":{"type":"number","example":45000},"dateRange":{"type":"object","properties":{"earliest":{"type":"string","example":"2018-11-01"},"latest":{"type":"string","example":"2026-02-06"}}},"generatedAt":{"type":"string","example":"2026-02-13T00:00:00.000Z"}},"xml":{"name":"main"}}}}},"404":{"description":"Feed not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Feed not found"},"feedId":{"type":"string","example":"1015378"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Feed not found"},"feedId":{"type":"string","example":"1015378"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/feeds/{feedId}":{"get":{"tags":["Corpus Discovery"],"summary":"Get a single feed by ID","description":"Returns details for a specific podcast feed.","parameters":[{"name":"feedId","in":"path","required":true,"schema":{"type":"string"},"description":"Feed identifier"}],"responses":{"200":{"description":"Feed details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Feed"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Feed"}},"xml":{"name":"main"}}}}},"404":{"description":"Feed not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Feed not found"},"feedId":{"type":"string","example":"1015378"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Feed not found"},"feedId":{"type":"string","example":"1015378"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/feeds/{feedId}/episodes":{"get":{"tags":["Corpus Discovery"],"summary":"List episodes for a feed","description":"Returns a paginated list of episodes for a specific feed, with optional date filtering and sort order.","parameters":[{"name":"feedId","in":"path","required":true,"schema":{"type":"string"},"description":"Feed identifier"},{"name":"limit","in":"query","description":"Results per page (default: 50, max: 200)","required":false,"schema":{"type":"integer"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer"}},{"name":"sort","in":"query","description":"Sort order: newest (default) or oldest","required":false,"enum":["newest","oldest"],"schema":{"type":"string"}},{"name":"minDate","in":"query","description":"Minimum published date (ISO format)","required":false,"schema":{"type":"string"}},{"name":"maxDate","in":"query","description":"Maximum published date (ISO format)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated episode list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Episode"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Episode"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/episodes/{guid}":{"get":{"tags":["Corpus Discovery"],"summary":"Get a single episode by GUID","description":"Returns details for a specific episode by its GUID.","parameters":[{"name":"guid","in":"path","required":true,"schema":{"type":"string"},"description":"Episode GUID"}],"responses":{"200":{"description":"Episode details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Episode"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Episode"}},"xml":{"name":"main"}}}}},"404":{"description":"Episode not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Episode not found"},"guid":{"type":"string","example":"abc123"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Episode not found"},"guid":{"type":"string","example":"abc123"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/episodes/{guid}/chapters":{"get":{"tags":["Corpus Discovery"],"summary":"List chapters for an episode","description":"Returns a paginated list of chapters for a specific episode, sorted by start time.","parameters":[{"name":"guid","in":"path","required":true,"schema":{"type":"string"},"description":"Episode GUID"},{"name":"limit","in":"query","description":"Results per page (default: 50, max: 200)","required":false,"schema":{"type":"integer"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated chapter list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Chapter"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Chapter"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/topics":{"get":{"tags":["Corpus Discovery"],"summary":"List aggregated topics","description":"Returns aggregated topics derived from chapter keywords, sorted by frequency. Optionally filter by feedId.","parameters":[{"name":"feedId","in":"query","description":"Filter topics to a specific feed","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results per page (default: 50, max: 200)","required":false,"schema":{"type":"integer"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated topic list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/people":{"get":{"tags":["Corpus Discovery"],"summary":"List people (creators and guests)","description":"Returns a paginated list of people (podcast creators and guests), sorted by number of appearances. Supports filtering by role, name search, and feed.","parameters":[{"name":"guestsOnly","in":"query","description":"Exclude hosts/creators, only show guests (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Partial name match (case-insensitive)","required":false,"schema":{"type":"string"}},{"name":"feedId","in":"query","description":"Filter to a specific podcast","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results per page (default: 50, max: 200)","required":false,"schema":{"type":"integer"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated people list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Person"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"query":{"type":"object","properties":{"guestsOnly":{"type":"boolean","example":false},"search":{},"feedId":{}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Person"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"query":{"type":"object","properties":{"guestsOnly":{"type":"boolean","example":false},"search":{},"feedId":{}}}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/corpus/people/episodes":{"post":{"tags":["Corpus Discovery"],"summary":"Get episodes featuring a person","description":"Returns a paginated list of episodes that feature a specific person (as guest or creator). Requires person name in request body.","parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"name":{"type":"string","example":"Elon Musk"},"guestsOnly":{"type":"boolean","example":false},"feedId":{"type":"string","example":""},"limit":{"type":"number","example":50},"page":{"type":"number","example":1}}}}],"responses":{"200":{"description":"Paginated episodes featuring the person","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string","example":"abc123"},"title":{"type":"string","example":"#252 - Elon Musk: SpaceX, Mars..."},"feedId":{"type":"string","example":"123"},"feedTitle":{"type":"string","example":"Lex Fridman Podcast"},"publishedDate":{"type":"string","example":"2024-03-15"},"role":{"type":"string","example":"guest"},"imageUrl":{"type":"string","example":"https://..."},"duration":{"type":"string","example":"2:30:00"}}}},"pagination":{"$ref":"#/components/schemas/Pagination"},"query":{"type":"object","properties":{"name":{"type":"string","example":"Elon Musk"},"guestsOnly":{"type":"boolean","example":false},"feedId":{}}}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string","example":"abc123"},"title":{"type":"string","example":"#252 - Elon Musk: SpaceX, Mars..."},"feedId":{"type":"string","example":"123"},"feedTitle":{"type":"string","example":"Lex Fridman Podcast"},"publishedDate":{"type":"string","example":"2024-03-15"},"role":{"type":"string","example":"guest"},"imageUrl":{"type":"string","example":"https://..."},"duration":{"type":"string","example":"2:30:00"}}}},"pagination":{"$ref":"#/components/schemas/Pagination"},"query":{"type":"object","properties":{"name":{"type":"string","example":"Elon Musk"},"guestsOnly":{"type":"boolean","example":false},"feedId":{}}}},"xml":{"name":"main"}}}}},"400":{"description":"Missing or invalid name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Bad request"},"message":{"type":"string","example":"name is required in request body"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Bad request"},"message":{"type":"string","example":"name is required in request body"}},"xml":{"name":"main"}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/agent/balance":{"get":{"tags":["Agent Auth"],"summary":"Check remaining balance","description":"Returns the remaining USD balance for the given L402 credential. Requires Authorization header with format: L402 <macaroon>:<preimage>","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}},{"name":"Authorization","in":"header","required":true,"description":"L402 credential in format: L402 <base64_macaroon>:<hex_preimage>","schema":{"type":"string"}}],"responses":{"200":{"description":"Balance retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"balanceUsd":{"type":"number","example":4.8},"balanceUsdMicro":{"type":"number","example":4800000},"totalDepositedUsd":{"type":"number","example":5},"totalDepositedUsdMicro":{"type":"number","example":5000000},"usedUsd":{"type":"number","example":0.2},"usedUsdMicro":{"type":"number","example":200000},"btcUsdRate":{"type":"number","example":100000},"clientId":{"type":"string","example":"optional-session-id"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"balanceUsd":{"type":"number","example":4.8},"balanceUsdMicro":{"type":"number","example":4800000},"totalDepositedUsd":{"type":"number","example":5},"totalDepositedUsdMicro":{"type":"number","example":5000000},"usedUsd":{"type":"number","example":0.2},"usedUsdMicro":{"type":"number","example":200000},"btcUsdRate":{"type":"number","example":100000},"clientId":{"type":"string","example":"optional-session-id"}},"xml":{"name":"main"}}}}},"401":{"description":"Missing or invalid Authorization header","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Unauthorized"},"message":{"type":"string","example":"Valid L402 Authorization header required"}},"xml":{"name":"main"}}},"application/xml":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Unauthorized"},"message":{"type":"string","example":"Valid L402 Authorization header required"}},"xml":{"name":"main"}}}}},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"},"503":{"description":"Service Unavailable"}}}},"/api/search-quotes-3d":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"example":"any"},"feedIds":{"example":"any"},"guid":{"example":"any"},"guids":{"example":"any"},"limit":{"example":"any"},"minDate":{"example":"any"},"maxDate":{"example":"any"},"episodeName":{"example":"any"},"fastMode":{"example":"any"},"extractAxisLabels":{"example":"any"},"createSession":{"example":"any"},"smartMode":{"example":"any"}}}}}}}},"/api/search-quotes-3d/expand":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"example":"any"},"queries":{"example":"any"},"fastMode":{"example":"any"},"extractAxisLabels":{"example":"any"}}}}}}}},"/api/fetch-research-id":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"researchSessionId":{"example":"any"},"fastMode":{"example":"any"},"extractAxisLabels":{"example":"any"},"forceRecompute":{"example":"any"}}}}}}}},"/api/episode-with-chapters/{guid}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"guid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/fetch-adjacent-paragraphs":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"paragraphId","in":"query","schema":{"type":"string"}},{"name":"adjacentSteps","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"500":{"description":"Internal Server Error"}}}},"/api/get-hierarchy":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"paragraphId","in":"query","schema":{"type":"string"}},{"name":"chapterId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/discover-podcasts":{"post":{"tags":["Discovery"],"summary":"LLM-assisted podcast discovery across the Podcast Index catalog","description":"Takes a natural language query, classifies intent via LLM, and routes to the appropriate Podcast Index search backends (byterm, byperson, trending). Returns matching podcasts enriched with transcript availability flags and actionable next-step endpoints. Use for deep research, person dossiers, prospecting prep, competitive intelligence, or topic exploration.\\n\\nA metered free tier is available: send the header `X-Free-Tier: true` to use quota-based access without payment. Anonymous users get 10 queries per week; registered users get 30 per month. Omit the header (or use L402 credentials) for paid access.","parameters":[{"name":"body","in":"body","required":true,"schema":{"type":"object","properties":{"query":{"type":"string","example":"bitcoin mining podcasts"},"limit":{"type":"number","example":10}}}}],"responses":{"200":{"description":"OK"},"500":{"description":"Internal Server Error"}}}},"/api/rss/searchFeeds":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"502":{"description":"Bad Gateway"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"podcastName":{"example":"any"}}}}}}}},"/api/rss/searchByPerson":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"502":{"description":"Bad Gateway"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"example":"any"}}}}}}}},"/api/rss/getFeed":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"502":{"description":"Bad Gateway"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"feedUrl":{"example":"any"},"feedId":{"example":"any"},"limit":{"example":"any"},"skipCleanGuid":{"example":"any"}}}}}}}},"/api/admin/entitlements/stats":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"500":{"description":"Internal Server Error"}}}},"/api/admin/entitlements/reset":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"entitlementType":{"example":"any"}}}}}}}},"/api/admin/entitlements/identifier/{identifierType}/{identifier}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"identifierType","in":"path","required":true,"schema":{"type":"string"}},{"name":"identifier","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"500":{"description":"Internal Server Error"}}}},"/api/admin/entitlements/update":{"put":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"identifier":{"example":"any"},"identifierType":{"example":"any"},"entitlementType":{"example":"any"},"updates":{"example":"any"}}}}}}}},"/api/admin/entitlements/cleanup":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","responses":{"200":{"description":"OK"},"500":{"description":"Internal Server Error"}}}},"/api/debug/episode/{guid}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"guid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/debug/paragraph-with-episode/{paragraphId}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"paragraphId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/debug/feed/{feedId}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"feedId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/debug/paragraph-with-feed/{paragraphId}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"paragraphId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/debug/text-for-timerange/{guid}/{startTime}/{endTime}":{"get":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"guid","in":"path","required":true,"schema":{"type":"string"}},{"name":"startTime","in":"path","required":true,"schema":{"type":"string"}},{"name":"endTime","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not Found"},"500":{"description":"Internal Server Error"}}}},"/api/debug/twitter/test-auth":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Unauthorized"},"500":{"description":"Internal Server Error"}}}},"/api/debug/twitter/test-media-upload":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"400":{"description":"Bad Request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal Server Error"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"example":"any"}}}}}}}},"/api/debug/twitter/clear-tokens":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Unauthorized"},"500":{"description":"Internal Server Error"}}}},"/api/debug/twitter/test-revoke":{"post":{"tags":["Pull"],"summary":"Run an LLM-orchestrated research query (JSON by default, SSE on opt-in)","description":"Dispatches a natural-language query to the Jamie research agent. The agent autonomously runs a sequence of tools (semantic quote search, chapter lookup, person resolution, podcast discovery) across one or more rounds, then composes a final answer with quoted passages and episode metadata. RESPONSE MODE: Defaults to a single JSON body (` {  sessionId, text, suggestedActions }","parameters":[{"name":"authorization","in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Unauthorized"},"500":{"description":"Internal Server Error"}}}}},"components":{"securitySchemes":{"L402Credential":{"type":"apiKey","in":"header","name":"Authorization","description":"L402 credential in format \"L402 <base64_macaroon>:<hex_preimage>\". Obtained by paying a Lightning invoice from a 402 challenge."},"BearerJWT":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated user sessions."},"ClientId":{"type":"apiKey","in":"header","name":"X-Client-Id","description":"Anonymous client identifier for session tracking without authentication."}},"schemas":{"Pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"totalPages":{"type":"integer","example":5},"totalCount":{"type":"integer","example":250},"limit":{"type":"integer","example":50},"hasMore":{"type":"boolean","example":true}}},"Feed":{"type":"object","properties":{"feedId":{"type":"string","example":"1015378"},"title":{"type":"string","example":"What Bitcoin Did"},"author":{"type":"string","example":"Peter McCormack"},"description":{"type":"string"},"episodeCount":{"type":"integer","example":824},"imageUrl":{"type":"string","format":"uri"},"hosts":{"type":"array","items":{"type":"string"},"description":"Host/owner names (empty array if not yet tagged)","example":["Peter McCormack"]},"feedType":{"type":"string","enum":["interview","solo","panel","narrative","mixed"],"nullable":true,"description":"Show format classification (null if not yet determined)"}}},"Episode":{"type":"object","properties":{"guid":{"type":"string"},"title":{"type":"string"},"creator":{"type":"string"},"description":{"type":"string"},"publishedDate":{"type":"string"},"duration":{"type":"string"},"imageUrl":{"type":"string","format":"uri"},"guests":{"type":"array","items":{"type":"string"}}}},"Chapter":{"type":"object","properties":{"pineconeId":{"type":"string"},"chapterNumber":{"type":"integer"},"headline":{"type":"string"},"keywords":{"type":"array","items":{"type":"string"}},"summary":{"type":"string"},"startTime":{"type":"number"},"endTime":{"type":"number"},"duration":{"type":"number"}}},"Topic":{"type":"object","properties":{"keyword":{"type":"string","example":"artificial intelligence"},"count":{"type":"integer","example":150},"feeds":{"type":"array","items":{"type":"object","properties":{"feedId":{"type":"string"},"title":{"type":"string"}}}},"sampleEpisodes":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string"},"title":{"type":"string"}}}}}},"Person":{"type":"object","properties":{"name":{"type":"string","example":"Elon Musk"},"role":{"type":"string","enum":["guest","creator"]},"appearances":{"type":"integer","example":3},"feeds":{"type":"array","items":{"type":"object","properties":{"feedId":{"type":"string"},"title":{"type":"string"}}}},"recentEpisodes":{"type":"array","items":{"type":"object","properties":{"guid":{"type":"string"},"title":{"type":"string"},"publishedDate":{"type":"string"}}}}}},"SearchResult":{"type":"object","properties":{"shareUrl":{"type":"string","format":"uri"},"shareLink":{"type":"string"},"quote":{"type":"string"},"episode":{"type":"string"},"creator":{"type":"string"},"audioUrl":{"type":"string","format":"uri"},"episodeImage":{"type":"string","format":"uri"},"listenLink":{"type":"string"},"date":{"type":"string"},"similarity":{"type":"object","properties":{"combined":{"type":"number","example":0.8542},"vector":{"type":"number","example":0.8542}}},"timeContext":{"type":"object","properties":{"start_time":{"type":"number"},"end_time":{"type":"number"}}}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}},"L402Challenge":{"type":"object","description":"L402 Payment Required challenge. Also emitted as a WWW-Authenticate response header.","properties":{"type":{"type":"string","example":"https://pullthatupjamie.ai/l402/payment-required"},"title":{"type":"string","example":"Payment Required"},"status":{"type":"integer","example":402},"detail":{"type":"string","example":"Purchase credits to access this endpoint. Pay the Lightning invoice, then retry with Authorization: L402 <macaroon>:<preimage>"},"macaroon":{"type":"string","description":"Base64-encoded macaroon credential","example":"AgEDTDQwMgJCM..."},"invoice":{"type":"string","description":"BOLT-11 Lightning invoice string","example":"lnbc10u1p..."},"paymentHash":{"type":"string","example":"9f8a2b..."},"amountSats":{"type":"integer","example":1000},"amountUsd":{"type":"number","example":1},"btcUsdRate":{"type":"number","example":100000},"expiresAt":{"type":"string","format":"date-time"},"code":{"type":"string","description":"Machine-readable reason code.","enum":["PAYMENT_REQUIRED","AUTH_REQUIRED","NO_BALANCE","INSUFFICIENT_FUNDS","QUOTA_EXCEEDED"]},"creditInfo":{"type":"object","properties":{"model":{"type":"string","example":"credit"},"service":{"type":"string","example":"pullthatupjamie"},"message":{"type":"string"},"customAmount":{"type":"string"},"defaultSats":{"type":"integer"},"minSats":{"type":"integer"},"maxSats":{"type":"integer"},"balanceEndpoint":{"type":"string","example":"/api/agent/balance"},"responseHeaders":{"type":"array","items":{"type":"string"}}}}}}}}}