New: 13 caption styles
Jellypod Docs

Videos, shorts, and Voiceovers

Generate media, upload source files, check progress, and retrieve downloads through the API.

Use https://api.jellypod.com/v1 as the base URL. Authenticate each API request with Authorization: Bearer YOUR_API_KEY. Create a key in Developers.

Videos, shorts, and voiceovers have separate collections, matching Studio. A short appears under /shorts; a voiceover appears under /voiceovers.

Discover settings before creating

Call GET /videos/options, GET /shorts/options, or GET /voiceovers/options for each product's supported settings and default values. These are fixed product fallbacks, not anything saved for your organization; voiceover has no style selection.

Use these shared endpoints alongside product options:

EndpointUse
GET /accountCheck your organization, plan, and data.credits.balance.
GET /hostsFind a narrator owned by your organization.
GET /sourcesFind existing research or uploaded visual sources.

Prompt and voiceover creation require a narrator: call GET /hosts to find one, then send its ID in host_id, or up to four in host_ids for a video or Voiceover. Finished scripts resolve their bracketed speaker labels instead.

Create and retrieve media

ActionVideoShortVoiceover
CreatePOST /videosPOST /shortsPOST /voiceovers
ListGET /videosGET /shortsGET /voiceovers
RetrieveGET /videos/{id}GET /shorts/{id}GET /voiceovers/{id}
ProgressGET /videos/{id}/statusGET /shorts/{id}/statusGET /voiceovers/{id}/status
RetryPOST /videos/{id}/retryPOST /shorts/{id}/retryPOST /voiceovers/{id}/retry
DownloadGET /videos/{id}/downloadGET /shorts/{id}/downloadGET /voiceovers/{id}/download

Generation uses the same product credit rates as Studio. Status checks and downloads do not generate new content. Open the returned studio_url to edit narration or individual scenes.

Idempotency keys

Create and retry requests accept an optional Idempotency-Key header: 1 to 255 printable ASCII characters, without spaces. Without it, every request starts a new generation, including an automatic retry of a request whose response was lost. With it, resending the same request within 24 hours returns the original resource instead of generating again. Reusing a key with different inputs returns 409. A deliberate retry of a failed generation uses the retry endpoint and a new key.

The header applies to the product endpoints above and to POST /episodes/generate. Other writes do not gain idempotency protection from it.

Create a Video

Send this JSON to POST /videos:

{
  "prompt": "Explain how bees communicate, for a curious beginner.",
  "host_ids": ["host_id_1", "host_id_2"],
  "target_duration_seconds": 300,
  "language": "en",
  "orientation": "LANDSCAPE"
}

Video durations are 300, 420, 600, 900, or 1200 seconds; omit target_duration_seconds to default to 300 seconds. host_ids accepts one to four unique host IDs in cast order. A video may send one host_id instead, but a request cannot include both fields, and a narrator is required.

Create a short

{
  "prompt": "Explain how bees communicate, for a curious beginner.",
  "target_duration_seconds": 30,
  "background_music": true
}

Shorts support 30 or 60 seconds and default to 30. background_music is optional and defaults to on.

Create from a finished script

Videos and shorts accept script instead of prompt:

{
  "script": "[Alex]\nWelcome to the show.\n\n[Sam]\nToday we are explaining how bees communicate.",
  "style_id": "your_style_id"
}

Put [Character Name] on its own line before each turn. Each label matches an active character returned by GET /hosts, or assign Host IDs to labels explicitly with speaker_characters:

{
  "speaker_characters": [{ "label": "Alex", "character_id": "host_id_1" }]
}

Explicit assignments override name matching and must use active hosts; unmapped labels still match by name. Script mode does not accept host_id, host_ids, or source_ids. Video and short scripts support at most four speakers. style_id is required. Jellypod validates and resolves the complete script before starting Credit-bearing generation.

Create a Voiceover

First upload a supported document or image. Send this JSON to POST /voiceovers, replacing the example UUID with your source ID:

{
  "source_ids": ["00000000-0000-4000-8000-000000000001"],
  "direction": "Walk through the slides in order for new team members.",
  "captions_enabled": true,
  "visual_motion": "auto"
}

source_ids contains 1 to 10 unique uploaded-file source IDs in presentation order. The combined input can contain at most 50 visuals. Generation waits for Source processing and prepares missing visuals.

Omit target_duration_seconds for automatic duration based on the content. Explicit durations are 180, 300, 420, 600, 900, 1200, 1800, 2700, or 3600 seconds, subject to your plan's voiceover limit. direction accepts up to 4,000 characters. captions_enabled defaults to false. visual_motion defaults to auto, which zooms photos and holds document pages still. Send dynamic to zoom every visual or static to zoom none.

Optional settings

All three products accept language and orientation. In prompt mode, shorts accept one narrator in host_id; videos accept one to four narrators in host_ids and retain host_id as a one-narrator compatibility input. Voiceovers use the same narrator fields. language defaults to en when omitted, and orientation defaults to AUTO. Orientation accepts AUTO, LANDSCAPE, PORTRAIT, or SQUARE. Omitting orientation, or sending AUTO explicitly, means portrait for shorts and landscape for videos and voiceovers. Portrait and square are also supported for voiceovers.

Videos and shorts require exactly one of a nonblank prompt or script. Prompts accept up to 20,000 characters and scripts up to 75,000. Prompt mode also accepts style_id from product options and up to 100 unique source_ids for research. Style defaults to the product's default style when omitted, but script mode requires it. Processing sources can be attached immediately: the generation workflow waits before reading them. Missing, failed, or stalled sources are rejected. Complete the upload before attaching a newly reserved source.

background_music belongs to shorts. captions_enabled, direction, and visual_motion belong to voiceovers, which do not accept prompt or style_id.

Follow progress and download

Creation returns HTTP 202 with the resource in data, a Location header pointing to its status endpoint, and Retry-After: 10. Save data.id immediately. The resource also includes object, title, status, phase, error, generation_id, studio_url, host_id, host_ids, language, orientation, background_music, style_id, target_duration_seconds, created_at, and updated_at.

Poll the status endpoint. status is idle, generating, completed, or failed. Use phase for progress detail and error for a failure reason. Respect poll_after_seconds; generation can continue after your script stops.

Once generation completes, request /download. Its data contains id, object, and delivery:

  • {"kind":"available","url":"https://example.com/output.mp4","origin":"mux"} contains the download URL. The origin may also be storage.
  • {"kind":"preparing","reason":"rendition"} means the delivery file is still being prepared. The reason may also be ingest. Wait and check again.
  • {"kind":"unavailable"} means no downloadable output is available. Open the resource in Studio.

List endpoints accept limit (1 to 100, default 20) and an opaque cursor. They return {"data": [...]} with the newest items first. Follow the response's Link header with rel="next" for the next page; no next link means the end. Pagination metadata is in the HTTP header, not in the JSON body.

Upload a file for Voiceover

Request an upload slot with POST /sources/uploads, upload the bytes to data.upload.url with its method and headers, then call POST /sources/{id}/complete-upload. Use the actual byte size and MIME type. Upload slots expire at data.upload.expires_at. Send the API key only to Jellypod API endpoints, not the signed upload URL.

Files must be nonempty and no larger than 100 MiB (104,857,600 bytes). file_name must be a filename without directories, at most 255 characters; its extension must match mime_type. Optional title accepts 1 to 500 characters. Completion verifies the declared size, stored MIME type, and supported file signatures.

Voiceover supports these source types:

FileMIME type
PDFapplication/pdf
PowerPoint .pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
PNGimage/png
JPEG .jpg or .jpegimage/jpeg
WebPimage/webp

Other presentation formats (.ppt, .pptm, Keynote, OpenDocument) are not accepted for Voiceover; export to PDF or .pptx first.

A voiceover supports 50 pages or images combined across all its sources. Splitting a presentation into multiple files does not raise this total.

Other supported upload types can be used as research sources. API uploads do not accept video/*; use extracted audio instead. Use POST /sources for a URL, YouTube link, or inline text.

A source moves from awaiting_upload through processing to completed or error. Check GET /sources/{id}. Request a new slot if it expires or processing fails.

Handle errors and retries

Read the error before retrying. Correct invalid input, add credits when needed, and respect Retry-After for rate limits. A failed HTTP response does not prove that generation failed.

Errors can include a recovery object: an action such as correct_input, check_account, or retry, and, on a pre-execution rejection, an idempotency_key of reuse or new. This field is present even when the request sent no Idempotency-Key; follow it only when you sent one. A rejection proven to happen before generation started releases its key, so fix the input or account issue and resend with the same key when idempotency_key is reuse; new means start over with a different key.

If an idempotency conflict says acceptance is unresolved, check the resource ID in the error. Do not create again with a new key because the original request may be running. Completed requests replay their accepted response.

A resource with status: "failed" or an unstarted status: "idle" can be retried with POST /{collection}/{id}/retry. Send a new Idempotency-Key if the retry itself might be resent. The retry keeps the resource ID and starts a new generation attempt. Review the error and credits first.

Was this page helpful?