Skip to content
Jellypod
Esc
↑↓navigate↵open⌘Jpreview
On this page

Get started with the API

Programmatic access to the Jellypod platform.

The Jellypod API creates and manages hosts, sources, podcast episodes, videos, shorts, and voiceovers. A host in the API is a saved Character in Studio. Start with the Video, short, and Voiceover guide for creation, file uploads, progress, retries, and downloads.

For copyable request examples, see Source-to-media recipes.

Connect

API requests need a paid plan or the free trial. Create an organization API key in Developers. The API Keys tab is visible to admins and to members with permission to manage keys. Send requests to https://api.jellypod.com/v1 with this header:

Authorization: Bearer YOUR_API_KEY

Credits and usage

The API uses the same product credit rates and plan limits as Studio. Generation costs depend on the product and its settings. Check GET /account for your plan and available balance. Podcast rendering and publishing are free; status checks and downloads do not start new generation. See Understanding Credits for details.

Podcast generation and retries

For POST /episodes/generate and POST /episodes/import, send an optional Idempotency-Key header. Reuse the key only with the same request. For 24 hours, Jellypod then returns the original episode and workflow IDs without starting another generation. Reusing the key with different input returns 409. Without a key, every request starts a generation.

If acceptance is uncertain, check the episode ID in the error before creating another episode. Video, short, and voiceover create and retry endpoints accept the same optional key.

Choose episode outputs

Send outputs with POST /episodes/generate or POST /episodes/import to choose the files you need:

outputs Result
["audio"] MP3, without video work
["video"] MP4 with sound
["audio", "video"] Both files, available independently
[] Editable content and narration, without exported files

For example, add "outputs": ["audio"] to your existing generation request to get an MP3 without waiting for video. Poll GET /episodes/{episode_id}. Its outputs.audio and outputs.video each contain status, download_url, current, and error. A status of available supplies a download URL; preparing means the requested file is still being produced; failed reports an error; not_requested means no file of that format was requested. Audio can be available while video is still preparing. A video failure does not remove a successful audio file.

The episode’s status still describes publication (draft, published, or scheduled). Read progress.status for production: completed means narration and all requested files finished. With outputs: [], it means the editable content is ready. A completed request can still have content gaps, reported in progress.needs_attention.

Existing requests keep their behavior: render: true produces audio and video; render: false or omission of both fields leaves an editable draft. render is deprecated. Send either outputs or render; sending both is rejected. Generation uses credits; exporting saved content does not regenerate narration.

Export saved content

After editing in Studio, or generating with outputs: [], request files with:

POST /v1/episodes/{episode_id}/export
Content-Type: application/json
Idempotency-Key: your-unique-export-key

{"outputs": ["audio"]}

The export action accepts audio, video, or both and returns 202 with id, outputs, and progress. Its Location header points to the episode. Poll that URL at the returned interval. Export reuses current files when possible, produces missing or outdated files from saved content, and never publishes the episode. Publishing remains an explicit action.

A failed replacement preserves the previous successful download. current indicates whether the available file reflects the episode’s current content. Request export again with a new idempotency key to retry failed output work; use the same key only when resending an identical request after an uncertain response. The existing generation retry endpoint has different behavior and can charge generation credits again.

Download links are signed and expire. Storage links last 24 hours; fetch the episode or its download endpoint again for a fresh link. Store the episode ID rather than treating a signed URL as a permanent identifier.

Episode progress, retries, and downloads

Episodes share the status, retry, and download endpoints that videos, shorts, and voiceovers use. GET /episodes/{episode_id} still returns the full episode with its embedded progress.

Action Endpoint
Progress GET /episodes/{episode_id}/status
Retry POST /episodes/{episode_id}/retry
Download GET /episodes/{episode_id}/download
Export saved content POST /episodes/{episode_id}/export
Captions and watermark GET or PATCH /episodes/{episode_id}/video-settings

The video settings endpoints (also under /videos, /shorts, and /voiceovers) read and change caption visibility, caption style, and the watermark corner the next render uses. A value saved on the item overrides the podcast default for an episode and the organization default for a video, and null returns that field to its default. Upload new watermark images in Studio.

The status endpoint returns id, object (episode), status, phase, error, needs_attention, poll_after_seconds, and studio_url. While poll_after_seconds is above zero, the Retry-After header carries the same wait. failed means requested work could not finish; successful files remain available. A usable episode with gaps reports needs_attention as counts of unvoiced_lines, missing_visuals, and skipped_sources; fix them in Studio. It is null when nothing is missing.

Retry restarts an episode whose first generation failed, from the request that started it, and charges generation credits again. It returns 202 with the episode in data, a Location header pointing to the status endpoint, and Retry-After: 10. It accepts an optional Idempotency-Key. A 409 means nothing started: the episode is still generating, already has playable audio, or failed in a way another attempt cannot fix, and the error says what to do. Retry failed file production with POST /episodes/{episode_id}/export; this generation retry endpoint does not retry export work.

Download returns id, object, media, and delivery for the served render. Published and scheduled episodes keep serving that version until publication changes. Use the episode’s outputs download URLs to retrieve newer draft exports. Draft episodes can download each requested file as it finishes. Send media=video for the video file; the default is audio. delivery has the same available, preparing, and unavailable forms as product downloads.

Import script text

POST /episodes/import accepts script or transcript text. It maps bracketed speaker labels to hosts that already exist in your organization, or assigns Host IDs to labels explicitly with speaker_characters, and queues a new episode. A label matching no host, with no explicit assignment, is refused, rather than creating a Host for it: a 422 with reason: "unresolved_speakers" and a speakers array naming the unmatched labels. Create any host you plan to name first, with POST /hosts or in Studio, then use its exact name as the label or its ID in speaker_characters.

{
  "podcast_id": "podcast_id",
  "script": "[Host One]\nWelcome to the show. Today we're talking about how small daily habits can make a big difference.\n\n[Host Two]\nI love that topic. Let's start with the easiest habit someone can try this week."
}

Text import removes clearly unspoken titles, production rules, and visual or duration directions while preserving narration and inline delivery tags. Uncertain lines stay; if classification fails, text is imported as written and production notes may be narrated. Structured scripts keep the supplied text.

Imported text can contain up to 75,000 characters. Text longer than your plan’s maximum episode length is cut to that length. Content rejected by the speech provider also returns 422 and creates nothing. The episode stays editable without rendering by default. Set outputs: ["audio"] when you want an MP3, or request video or both formats. Poll GET /episodes/{episode_id} for progress and download URLs.

An unknown podcast_id, a speaker label matching no existing host, or text with no usable segments also return an error and create nothing. Sent with an Idempotency-Key, these input errors are rejected immediately, so fix the input and retry with the same key when recovery.idempotency_key is reuse. If cleanup failed or the rejection was stored under the older policy, recovery instead specifies new.

Generate from a prompt

Send prompt to POST /episodes/generate. You can include a duration in the prompt. Without one, the target is about 7 minutes.

You can also set the duration directly in options instead of relying on the prompt:

{
  "podcast_id": "podcast_id",
  "prompt": "An episode about the history of beekeeping.",
  "options": {
    "episode_length_minutes": 15
  }
}

episode_length_minutes accepts an integer from 1 to 75 and defaults to 7. The retired episode_length and web_search options are still accepted but have no effect.

Episode prompt mode always writes a new script from the prompt and attached sources, even when they contain finished narration. To preserve raw script text, use POST /episodes/import with optional speaker_characters assignments.

Generate from a script

Send a structured script to POST /episodes/generate to use your own chapters and segments.

Use GET /hosts to fetch the host_id values available to your organization. Every segment must reference one of those hosts, and each host must be active. Imported script text is capped at 75,000 total characters across all segments.

{
  "podcast_id": "podcast_id",
  "script": {
    "chapters": [
      {
        "title": "Introduction",
        "segments": [
          {
            "host_id": "host_id_1",
            "text": "Welcome to the show. Today we're talking about how small daily habits can make a big difference."
          },
          {
            "host_id": "host_id_2",
            "text": "I love that topic. Let's start with the easiest habit someone can try this week."
          }
        ]
      }
    ]
  }
}

Rules for script generation:

  • Send either prompt or script, not both.
  • source_ids are only supported for prompt-based generation.
  • Script mode does not use web_search, episode_length, or episode_length_minutes.
  • Scripts can include up to 50 chapters, 200 segments per chapter, and 600 segments total. Each segment can contain up to 5,000 characters.
  • Long scripts require enough available credits before generation starts. The final charge is based on the narration audio generated, whether or not the episode is rendered.
  • Script generation creates a new episode.

Last updated on

Was this page helpful?