# Agent guide (/docs/api/agents)



Use Jellypod's MCP tools to create podcasts, Videos, Shorts, and Voiceovers in
the authenticated organization. Discover the available tools, choose a product,
then follow its returned resource ID until the output is ready.

HTTP clients use the same product services and permissions. REST requests go to
`https://api.jellypod.com/v1` with `Authorization: Bearer YOUR_API_KEY`; the
[live OpenAPI schema](https://api.jellypod.com/openapi.json) describes their
fields. MCP clients connect to `https://mcp.jellypod.com/mcp` with Streamable
HTTP, authenticate through OAuth or a bearer API key, and read `tools/list`.
See [connection setup](/docs/help/mcp) and the [MCP tool reference](/docs/api/mcp-tools).

Create API keys in [Developers](https://app.jellypod.com/developers/api-keys).
Keep keys in a secret store. Use resource IDs returned for the active
organization; a name, file path, or URL does not substitute for an ID.

For text-only documentation, read
[/llms.mdx/docs/api/agents](/llms.mdx/docs/api/agents). The
[/llms.txt](/llms.txt) index links the documentation, and
[/llms-full.txt](/llms-full.txt) provides the combined text.

## Choose the product [#choose-the-product]

| User's goal                                      | Product              | HTTP creation             | MCP creation                         |
| ------------------------------------------------ | -------------------- | ------------------------- | ------------------------------------ |
| A podcast episode from a brief                   | Episode in a Podcast | `POST /episodes/generate` | `generate_episode`, `mode: "brief"`  |
| A podcast episode from supplied narration        | Episode in a Podcast | `POST /episodes/import`   | `generate_episode`, `mode: "script"` |
| A narrated video with generated visuals          | Video                | `POST /videos`            | `generate_video`                     |
| A short narrated video with generated visuals    | Short                | `POST /shorts`            | `generate_short`                     |
| Narration over supplied document pages or images | Voiceover            | `POST /voiceovers`        | `generate_voiceover`                 |

Videos, Shorts, and Voiceovers are separate products. Selecting portrait
orientation on a Video does not turn it into a Short. Keep the product kind
with the returned ID for later reads and actions. Podcast Episodes use Podcast
Templates for their video output; use standalone Videos or Shorts for generated
visuals.

## Discover before creating [#discover-before-creating]

Call `get_creation_options` with `product` set to `episode`, `video`, `short`,
or `voiceover`. Use `section: "settings"` for product settings and
`section: "voices"` to browse voices. Use returned choices rather than inventing
IDs or copying another product's defaults.

Use `list_resources` to find existing content. For example:

```json
{
  "name": "list_resources",
  "arguments": { "kind": "host", "limit": 10 }
}
```

Voice discovery returns voice IDs for `save_host.voice_id`. Generation uses
saved Host IDs, not voice IDs. Select an existing narrator when possible. Use `save_host` with `mode: "create"`
to create a Host, and `save_podcast` with `mode: "create"` when a new podcast is
needed. To change either resource, use `mode: "update"` and its `id`. Read each
tool's schema for required creation fields and supported update fields.

For HTTP product defaults, use `GET /videos/options`, `/shorts/options`, or
`/voiceovers/options`. Host discovery uses `GET /hosts`. These REST names are
unchanged by the compact MCP tool set.

## Create a podcast episode [#create-a-podcast-episode]

1. Find the podcast and its narrator Hosts with `list_resources`. Resolve the
   user's intended show and voices before starting generation.
2. Read episode creation options. Choose `generate_episode` with `mode: "brief"`
   for generated content, or `mode: "script"` when narration is supplied.
3. Save a unique `idempotency_key` for the command and the returned episode ID.
4. Call `get_resource` with `kind: "episode"` and `id` to follow the result.
5. Use `set_episode_publication` only when publishing or scheduling is authorized.
   It takes `mode: "publish"`, `"schedule"`, or `"unpublish"`; scheduling requires
   `scheduled_time`.

Brief mode requires `prompt`. Script mode requires `script` and does not accept
`prompt`, `sources`, or `host_ids`; use bracketed speaker labels such as
`[Host Name]` in the narration. `idempotency_key` is optional for Episodes in
both modes, but save and send one to protect against a lost response. Episodes begin as drafts;
creation does not authorize publication. Use `update_episode` for supported
metadata changes, and Studio for detailed editing.

## Supply Sources [#supply-sources]

Videos and Shorts accept a prompt and optional research `source_ids`. Their
workflows can wait for valid processing Sources. Missing or failed Sources
must be corrected before generation.

Voiceovers accept supported document or image Sources. Preserve `source_ids`
order for the presentation. Generation waits for Source processing, prepares
missing visuals, and reuses existing preparation automatically.

For clients that can transfer files:

1. Call `request_source_upload` with `mode: "direct"`, file name, MIME type, and byte size.
2. Transfer the bytes to `upload.url` using the returned method and headers.
   Do not put base64 bytes in tool arguments or send the Jellypod API key to
   the storage URL.
3. Call `complete_source_upload` with the returned Source ID.
4. Create the intended product using the Source ID. Generation waits for
   processing automatically. Poll the returned product with `get_resource`.
   If generation reports a Source error, inspect that Source with
   `get_resource`, `kind: "source"`.

For an interactive file chooser, call `request_source_upload` with
`mode: "picker"`. This mode requires no file metadata
and returns a handoff, not an uploaded Source. Show the picker when supported;
otherwise open the returned `studio_url`. Do not assume `source` or `upload`
exists in a picker response.

If file transfer is unavailable, direct the user to
[Assets](https://app.jellypod.com/assets), then **New Asset**. Find the uploaded
file with `list_resources`, `kind: "source"`, and inspect it with `get_resource`.
Do not claim that an attachment was uploaded until the transfer succeeds.
The [upload walkthrough](/docs/api/products#upload-a-file-for-voiceover) provides
the HTTP flow and a runnable example.

## Generate once and follow the result [#generate-once-and-follow-the-result]

For Videos, Shorts, and Voiceovers, save a unique `idempotency_key` before
calling the generation tool. Reuse the key with unchanged input when resending
a request after a lost response. For example, these are `tools/call` parameters:

```json
{
  "name": "generate_short",
  "arguments": {
    "prompt": "Explain why leaves change color in autumn, for a beginner.",
    "target_duration_seconds": 30,
    "idempotency_key": "YOUR_SAVED_UNIQUE_REQUEST_KEY"
  }
}
```

For HTTP, send the same creation fields without `idempotency_key` in the JSON
body to `POST /shorts`, and put the key in the `Idempotency-Key` header. HTTP
returns `202` with the resource in `data`. This acknowledges acceptance; it
does not mean that the media is finished.

For MCP, check `isError` before interpreting the result as success. Read
`structuredContent` or the JSON text content. Save the returned product kind
and ID immediately. Follow it with a grouped read:

```json
{
  "name": "get_resource",
  "arguments": { "kind": "short", "id": "YOUR_SHORT_ID" }
}
```

The response contains `kind`, `id`, and `resource`, with progress, delivery,
transcript, and Studio links when applicable. This call replaces separate
product detail, status, and download tools. Product generation states include
`idle`, `generating`, `completed`, and `failed`. Display the returned phase and
respect `progress.poll_after_seconds`. Stop after a bounded polling period and retain the
ID; a polling deadline does not mean generation failed.

After completion, `delivery.kind: "available"` supplies a URL. If delivery is
`preparing`, wait and read the resource again. If it is `unavailable`, show the
Studio link. Do not generate again to obtain a missing download. Use Studio
for narration and scene edits.

## Distinguish resends from new attempts [#distinguish-resends-from-new-attempts]

* A resend uses the same key and unchanged input. Accepted commands replay their
  original result; use `get_resource` for current progress.
* Changed input with a reused key returns a conflict. Use a new key only for an
  intentionally different request.
* If acceptance is unresolved, retain the command ID and check the resource ID
  in the error. Do not use a new key while the original dispatch is uncertain.
* For a confirmed failed Video, Short, or Voiceover, `retry_generation` takes
  `kind`, `id`, and a new `idempotency_key`. Another paid attempt must be within
  the user's authorized scope. The resource ID stays the same.

Generation and deliberate retries spend credits. Reads and download lookups do
not start generation. Consult [credits](/docs/help/getting-started/understanding-credits)
and the tool's current schema before making a paid call. Idempotency protection
for generation does not make other writes, such as publishing or deletion,
idempotent.

## Text results and optional cards [#text-results-and-optional-cards]

Build the workflow around structured or text tool results. For GrokBot (xAI),
Claude, Codex, or another client, verify that the intended environment can
connect, authenticate, discover tools, and execute a resource read before
starting paid generation. Client versions and configurations differ; this
guide does not certify each client or its embedded UI support.

MCP Apps cards are optional presentation. A client without cards can still
follow IDs, inspect progress, and open returned URLs. Do not rely on a card to
perform a required workflow step. If the client cannot wait, report the resource
ID and let the user return to it later.
