> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pictory.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Use Pictory with an LLM

> Guide an LLM end-to-end through the Pictory API using llms.txt, the MCP server, OpenAPI, and proven system prompts

This guide shows you how to feed Pictory documentation to a Large Language Model (LLM) so the model can guide a user end-to-end — from describing a video they want, through building the right API payload, to retrieving the rendered video.

By the end of this page, you will have:

* A single URL you can paste into any LLM to make it Pictory-aware
* A system prompt that turns the model into a Pictory API assistant
* A reference list of example user prompts and the API calls they should produce
* A working setup for the Pictory MCP server so agentic tools can call the API directly

## Why This Matters

The Pictory API exposes many endpoints, dozens of optional fields, and several content-source types (text, blog URLs, PowerPoint, audio, video). A user describing their goal in natural language ("create a 60-second product demo with a chef avatar") needs **a lot of context** to be translated correctly into a request payload. LLMs handle this translation well — when given the right context.

The pieces below give an LLM that context.

***

## 1. Point an LLM at `llms.txt` or `llms-full.txt`

Pictory's documentation site automatically generates two machine-friendly bundles you can feed to any LLM:

| File            | URL                                     | What It Contains                                                  | When to Use                               |
| --------------- | --------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------- |
| `llms.txt`      | `https://docs.pictory.ai/llms.txt`      | Index of all docs pages with titles and one-line descriptions     | Quick navigation, smaller context windows |
| `llms-full.txt` | `https://docs.pictory.ai/llms-full.txt` | **Entire documentation site concatenated into one Markdown file** | Maximum accuracy, large context windows   |

### How to Use

**Option A — Paste into a chat session.**

Open any LLM chat (Claude, ChatGPT, Perplexity, Gemini) and paste the URL or the contents of `llms-full.txt` at the top of the conversation. Then ask your question normally.

**Option B — Use the per-page Copy/Open buttons.**

Every page on `docs.pictory.ai` has a "Copy" menu in the top-right with these options: **Copy as Markdown**, **Open in ChatGPT**, **Open in Claude**, **Open in Perplexity**, **Open in MCP**, **Open in Cursor**, **Open in VSCode**. Use these when you need context from a single page.

**Option C — Reference the URL programmatically.**

If you are building an agent or chatbot, fetch `llms-full.txt` once per session and pass it as a system prompt or context block:

<CodeGroup>
  ```javascript Node.js theme={null}
  const docsContext = await fetch("https://docs.pictory.ai/llms-full.txt")
    .then((r) => r.text());

  const systemPrompt = `${PICTORY_SYSTEM_PROMPT}\n\n## Pictory Docs\n\n${docsContext}`;
  ```

  ```python Python theme={null}
  import requests

  docs_context = requests.get("https://docs.pictory.ai/llms-full.txt").text
  system_prompt = f"{PICTORY_SYSTEM_PROMPT}\n\n## Pictory Docs\n\n{docs_context}"
  ```
</CodeGroup>

<Note>
  `llms-full.txt` is large. If your model's context window is small, prefer `llms.txt` and use the per-page Markdown URLs for the specific pages the user's question touches.
</Note>

***

## 2. Use the Pictory OpenAPI Spec

For deterministic codegen and structured tool use, the Pictory API publishes an OpenAPI 3.1 specification:

`https://docs.pictory.ai/openapi.json`

You can:

* Feed this directly to an LLM as a structured tool schema
* Generate client SDKs in any language (TypeScript, Python, Go, Ruby, etc.) using `openapi-generator` or `openapi-typescript`
* Import into Postman, Insomnia, or any API client for interactive testing

<Tip>
  When you give an LLM both the OpenAPI spec and `llms-full.txt`, you get the best of both worlds — the structured field-level validation from OpenAPI, plus the narrative guidance and examples from the docs.
</Tip>

***

## 3. Recommended System Prompt

Paste this as the system prompt (or the first message) in any LLM you want to act as a Pictory API assistant:

```markdown theme={null}
You are a Pictory API assistant. You help users create videos programmatically using the Pictory API.

## Core Knowledge

- **Authentication:** The Pictory API uses a direct API key in the `Authorization` header. The key starts with `pictai_`. Do NOT use a `Bearer` prefix. The header value is the raw key.
- **Base URL:** `https://api.pictory.ai/pictoryapis`
- **Primary endpoints:**
  - `POST /v2/video/storyboard` — Create a storyboard preview (review before rendering)
  - `POST /v2/video/storyboard/render` — Render the final video directly
  - `POST /v2/projects/{projectid}/render` — Re-render an existing project
  - `GET /v1/jobs/{jobid}` — Fetch the status and output of any job
  - `GET /v1/brands/video` — List the user's video brand kits

## How to Help

1. Ask the user what they want to create (text-to-video, PPT-to-video, avatar video, template-based, etc.).
2. Identify the right endpoint based on the input source.
3. Build a complete, valid request payload — never use placeholder values for required fields without flagging them.
4. Surface mutually exclusive fields (e.g., `brandId` vs `brandName`, `smartLayoutId` vs `smartLayoutName`, `subtitleStyleId` vs `subtitleStyleName`).
5. Always show how to poll the job status using `GET /v1/jobs/{jobid}` afterward, OR recommend the `webhook` field for async notification.
6. Include language hints when relevant. Supported `language` values: `zh, nl, en, fr, de, hi, it, ja, ko, mr, pt, ru, es, ta`.

## Dynamic IDs — Never Invent These

The following fields take **account-scoped IDs that must be discovered at runtime**. Do NOT hallucinate values; do NOT memorize examples from training data. Call the discovery endpoint first, then use a real ID from the response.

| Field | Discovery endpoint | Notes |
|---|---|---|
| `avatar.avatarId` | `GET /v1/avatars` | Lists AI avatars available to the user's account |
| `brandId` / `brandName` | `GET /v1/brands/video` | Lists the user's saved brand kits |
| `templateId` | `GET /v2/projects` or `GET /v1/templates` | Either an existing project ID (used as a template) or a saved template ID |
| `smartLayoutId` / `smartLayoutName` | `GET /v1/smartlayouts` | Lists available smart layouts |
| `subtitleStyleId` / `subtitleStyleName` | `GET /v1/styles` | Lists saved subtitle styles |
| `voiceOver.aiVoices[].speaker` | `GET /v1/voiceovers/tracks` | Lists available AI voices |

**Workflow:** when a user says "use my chef avatar", do not guess an ID. Either ask them for the ID explicitly, or instruct them to run `GET /v1/avatars` and pick from the response. The same applies to brands, templates, layouts, subtitle styles, and voices.

### Default Voice by Language

When the user does not specify a voice but does specify a language, use the documented default male STD voice for that language. For languages without a documented default, the API falls back to the English default; in that case it is often better to call `GET /v1/voiceovers/tracks` and pick a native-language voice explicitly.

| `language` | Default male STD voice | Notes |
|---|---|---|
| `en` | `Martin` | |
| `nl` | `Tim` | Dutch |
| `fr` | `Gabriel` | French |
| `de` | `Wilbur` | German |
| `it` | `Marco` | Italian |
| `pt` | `Aurelio` | Portuguese |
| `es` | `Hugo` | Spanish |
| `hi` | `Martin` | Hindi — falls back to English |
| `ru` | `Martin` | Russian — falls back to English |
| `zh`, `ja`, `ko`, `mr`, `ta` | (none documented) | Discover a native voice via `GET /v1/voiceovers/tracks` |

This table covers the documented STD male defaults. For female voices or non-default catalogs, call the voiceovers tracks endpoint and let the user choose.

## Output Format

When generating an API call, always output:

1. A short summary of what the call will do (one sentence).
2. The complete cURL command (with `YOUR_API_KEY` as the placeholder).
3. A note about the response shape and how to retrieve the rendered video.

## Common Pitfalls to Avoid

- Do not invent endpoints. If you are unsure, ask the user to confirm or reference the docs.
- Do not invent or hallucinate IDs (`avatarId`, `brandId`, `templateId`, `smartLayoutId`, `subtitleStyleId`, voice `speaker`). Always discover them via the listing endpoints above.
- Do not use `Bearer` in the Authorization header — Pictory uses the raw key.
- Do not omit `videoName` (required) on render endpoints.
- Do not include both `brandId` and `brandName` in the same request — the API rejects this.
- Do not place `avatarId` inside a scene's `avatar` field. The avatar identity is set once at the top level (`avatar.avatarId`); per-scene `avatar` accepts only position and styling overrides.
- API render jobs are NOT saved as projects unless `saveProject: true` is passed (or `templateId` is provided to render against an existing project).
- Scene `elements` (shape and text overlays) live inside each scene's `elements` array. Maximum 20 per scene. Any scene that includes `elements` is routed to the v3 storyboard engine automatically — do not set `storyboardVersion`. See the [Scene Elements guide](/guides/advanced-features/scene-elements) for the full shape catalog and field reference.

## Reference Documentation

For complete details, refer to `https://docs.pictory.ai/llms-full.txt` and `https://docs.pictory.ai/openapi.json`.
```

***

## 4. Pictory MCP Server

For agentic LLM tools (Claude Desktop, Cursor, Windsurf, custom agents built on the MCP protocol), Pictory provides an **MCP server** that exposes the API as structured tools. The agent can invoke endpoints directly without you having to handcraft requests.

Learn more and grab the connection details at [Pictory MCP Server](https://pictory.ai/pictory-mcp-server-api).

Setup pages for popular agentic tools:

* [Claude Code setup](/ai-tools/claude-code)
* [Cursor setup](/ai-tools/cursor)
* [Windsurf setup](/ai-tools/windsurf)

***

## 5. Example Prompts and Expected API Calls

These examples show the natural-language input a user might give and the API call an LLM (configured per the system prompt above) should produce.

### Example 1 — Simple text-to-video

> "Create a 30-second product demo video about our new coffee maker. Use an upbeat AI voice."

Expected endpoint: `POST /v2/video/storyboard/render`

```json theme={null}
{
  "videoName": "Coffee Maker Demo",
  "language": "en",
  "aspectRatio": "16:9",
  "scenes": [
    { "story": "Introducing the BrewMax 3000 — your morning, simplified.", "createSceneOnEndOfSentence": true },
    { "story": "One-touch brewing, three temperature presets, and a sleek glass carafe.", "createSceneOnEndOfSentence": true },
    { "story": "BrewMax 3000. Order yours today.", "createSceneOnEndOfSentence": true }
  ],
  "voiceOver": {
    "enabled": true,
    "aiVoices": [{ "speaker": "Martin", "speed": 100, "amplificationLevel": 0 }]
  }
}
```

### Example 2 — PPT-to-video in another language

> "Convert this PowerPoint deck into a French training video with speaker notes as narration: [https://example.com/training.pptx](https://example.com/training.pptx)"

Expected endpoint: `POST /v2/video/storyboard/render`

```json theme={null}
{
  "videoName": "French Training Video",
  "language": "fr",
  "scenes": [
    {
      "pptUrl": "https://example.com/training.pptx",
      "useSpeakerNotes": true
    }
  ],
  "voiceOver": {
    "enabled": true,
    "aiVoices": [{ "speaker": "Gabriel", "speed": 100, "amplificationLevel": 0 }]
  }
}
```

### Example 3 — Avatar video using a saved template

> "Use my brand template and render a video where my Chef avatar walks through 4 recipe steps."

Before generating the payload, the LLM should fetch the available avatars and templates so it uses real IDs from the user's account:

```bash theme={null}
curl -H 'Authorization: YOUR_API_KEY' https://api.pictory.ai/pictoryapis/v1/avatars
curl -H 'Authorization: YOUR_API_KEY' https://api.pictory.ai/pictoryapis/v2/projects
```

Then build the payload with real IDs (the placeholders below are stand-ins for values picked from the discovery responses):

Expected endpoint: `POST /v2/video/storyboard/render`

```json theme={null}
{
  "videoName": "Recipe — Lemon Risotto",
  "templateId": "<projectId from /v2/projects>",
  "avatar": {
    "avatarId": "<avatarId from /v1/avatars>"
  },
  "scenes": [
    { "story": "Today we are making lemon risotto. Here are the ingredients." },
    { "story": "Step 1: Heat the pan and toast the rice." },
    { "story": "Step 2: Add lemon zest and stock, stirring continuously." },
    { "story": "Step 3: Plate and serve with parmesan." }
  ]
}
```

### Example 4 — Blog URL to video

> "Turn this blog post into a one-minute video with subtitles: [https://example.com/blog/our-launch](https://example.com/blog/our-launch)"

Expected endpoint: `POST /v2/video/storyboard/render`

```json theme={null}
{
  "videoName": "Blog to Video — Launch Post",
  "language": "en",
  "aspectRatio": "16:9",
  "scenes": [
    {
      "blogUrl": "https://example.com/blog/our-launch"
    }
  ],
  "voiceOver": {
    "enabled": true,
    "aiVoices": [{ "speaker": "Martin", "speed": 100, "amplificationLevel": 0 }]
  }
}
```

<Tip>
  The Pictory backend fetches and summarizes the blog content automatically. The resulting scenes are derived from the article structure. Each scene in the `scenes` array must contain exactly one content source — `story`, `blogUrl`, `pptUrl`, `audioUrl`, `videoUrl`, or `storyCoPilot` — never mix sources within a single scene.
</Tip>

### Example 5 — Storyboard preview, then render-from-preview

> "Generate a preview first so I can review the scenes before paying for a full render."

This is a two-step flow. The LLM should produce both steps.

**Step 1 — Create the preview:**

Expected endpoint: `POST /v2/video/storyboard`

```json theme={null}
{
  "videoName": "Preview-First Demo",
  "language": "en",
  "scenes": [
    { "story": "First scene narration text.", "createSceneOnEndOfSentence": true },
    { "story": "Second scene narration text.", "createSceneOnEndOfSentence": true }
  ],
  "voiceOver": {
    "enabled": true,
    "aiVoices": [{ "speaker": "Martin", "speed": 100, "amplificationLevel": 0 }]
  }
}
```

The response contains a `jobId`. Poll `GET /v1/jobs/{jobid}` until the preview is `completed`; the response includes the storyboard scenes and metadata.

**Step 2 — Render from the preview:**

Expected endpoint: `PUT /v2/video/render/{storyboardjobid}`

```bash theme={null}
curl --request PUT \
  --url 'https://api.pictory.ai/pictoryapis/v2/video/render/<storyboardjobid from Step 1>' \
  --header 'Authorization: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{ "webhook": "https://your-domain.com/pictory-webhook" }'
```

The path parameter is the **preview job ID** from Step 1, not a project ID. The request body is optional — pass `webhook` here only if you want to override the webhook URL set during the preview step.

Use this two-step flow when the user wants to review or edit scenes before committing render resources. To edit scenes between the two steps, see the [Update Storyboard Elements API](/api-reference/video-storyboard/update-storyboard-elements).

### Example 6 — Polling job status

> "How do I check if my video at job ID `9b1c4d2e-7f8a-4321-b2c3-d456e789f012` is done?"

Expected endpoint: `GET /v1/jobs/{jobid}`

```bash theme={null}
curl --request GET \
  --url 'https://api.pictory.ai/pictoryapis/v1/jobs/9b1c4d2e-7f8a-4321-b2c3-d456e789f012' \
  --header 'Authorization: YOUR_API_KEY'
```

Poll every 10–30 seconds. When `data.status === "completed"`, the rendered video URL is in `data.videoURL`. For long-running renders, prefer passing a `webhook` URL in the render request body instead of polling.

***

## 6. Troubleshooting LLM Output

| Symptom                                                  | Cause                                           | Fix                                                                                                        |
| -------------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| LLM uses `Bearer YOUR_API_KEY`                           | Default training bias toward OAuth/Bearer flows | Restate the auth rule in your system prompt: "The `Authorization` header value is the raw key, no prefix." |
| LLM invents an endpoint                                  | Insufficient context                            | Feed `llms-full.txt` or `openapi.json` into the session                                                    |
| Render succeeds but video does not appear in My Projects | Missing `saveProject: true` and no `templateId` | Tell the LLM: "Always include `saveProject: true` unless the user passes a `projectId` as `templateId`."   |
| LLM passes both `brandId` and `brandName`                | Field-level constraint not in training data     | Reinforce in system prompt; the API rejects both-together                                                  |
| Polling returns 404                                      | Wrong job type or wrong account                 | Verify the API key matches the account that submitted the job                                              |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="MCP Server" icon="plug" href="https://pictory.ai/pictory-mcp-server-api">
    Connect agentic tools directly to the Pictory API
  </Card>

  <Card title="Claude Code Setup" icon="terminal" href="/ai-tools/claude-code">
    Wire Claude Code into the Pictory API
  </Card>

  <Card title="Cursor Setup" icon="arrow-pointer" href="/ai-tools/cursor">
    Configure Cursor to call Pictory endpoints
  </Card>

  <Card title="Windsurf Setup" icon="water" href="/ai-tools/windsurf">
    Configure Windsurf for Pictory automation
  </Card>

  <Card title="End-to-End Recipes" icon="book-open" href="/guides/recipes/end-to-end-recipes">
    Complete working JSON payloads for common use cases
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference">
    Endpoint-by-endpoint reference
  </Card>
</CardGroup>
