> For the complete documentation index, see [llms.txt](https://developers.gamma.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.gamma.app/get-started/migrate-from-classic-to-gamma-5.md).

# Migrate from Classic to Gamma 5

Move a Classic text-to-PPTX integration to Gamma 5 agent generation, with a before/after example and a prompt for your coding agent.

Classic generation (`POST /v1.0/generations`) keeps working, so nothing breaks if you stay on it. Gamma 5 (`POST /v1.0/agent/generations`) is the recommended path: you describe the outcome and the Gamma agent plans, writes, and designs the gamma. This page uses a text-to-PPTX integration as the worked example; the same changes apply to other Classic integrations, including PDF or PNG exports and calls with no export. It also lists what to check before you switch traffic.

## Quick reference

* Create with `POST /v1.0/agent/generations` and send `prompt` instead of `inputText`. Unknown fields such as `textMode` or `textOptions` are rejected with `400`, so remove them.
* Poll `GET /v1.0/agent/generations/{generationId}` (ids start with `gen_`). The gamma's id and URL move under `gamma`: `gamma.gammaId` and `gamma.gammaUrl`.
* Tone, audience, and language become written instructions in `prompt` or `additionalInstructions`. Image, card layout, and header/footer controls have no direct equivalent.
* `numCards` is a soft target. Branding needs an explicit `themeId` or `templateId`; there is no workspace default theme.
* `exportAs: "pptx"` still works. A `completed` generation can still be missing its file: check that `exportUrl` exists and handle the `export_failed` warning.
* Classic `from-template` calls move to `templateId` on the same endpoint; see [Migrate `from-template` calls](#migrate-from-template-calls).
* Agent jobs are priced by the work the agent does. Read `credits.deducted` from the completed or failed response.

## What changes

|                    | Classic                                                 | Gamma 5                                                                      |
| ------------------ | ------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Create             | `POST /v1.0/generations`                                | `POST /v1.0/agent/generations`                                               |
| Content            | `inputText` + `textMode`                                | `prompt` (the brief and any source text)                                     |
| Style and audience | `textOptions.tone`, `.audience`, `.language`, `.amount` | Instructions in `prompt` or `additionalInstructions`                         |
| Poll               | `GET /v1.0/generations/{id}`                            | `GET /v1.0/agent/generations/{generationId}`                                 |
| Result             | Top-level `gammaId`, `gammaUrl`, `exportUrl`            | `gamma.gammaId`, `gamma.gammaUrl`, `exportUrl`, `result.summary`, `warnings` |
| Pricing            | Per card and per image                                  | By the work the agent does                                                   |

Both endpoints use the same API key in the `X-API-KEY` header, the same `exportAs` values (`pdf`, `pptx`, `png`), and the same credit balance. `themeId`, `folderId`, and `sharingOptions` carry over with the same meaning. For the full comparison, see [Explore the API](/get-started/understanding-the-api-options.md).

## Before and after: text to PPTX

This is an example. For PDF or PNG (a ZIP of PNGs), change `exportAs` everywhere it appears and the download file name; with no export, drop `exportAs` and stop at `gamma.gammaUrl`, skipping the export fallback and download. Both versions turn the same source text into a branded 10-slide deck for the same audience, poll until the job finishes, and download the PPTX. They read `GAMMA_API_KEY` and `GAMMA_THEME_ID` (an `id` from [`GET /themes`](/workspace/list-themes.md)) from the environment.

### Request mapping

The same request in each API, so you can map fields one to one:

{% tabs %}
{% tab title="Before (Classic)" %}

```bash
curl -X POST https://public-api.gamma.app/v1.0/generations \
  -H "X-API-KEY: $GAMMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputText": "<contents of q3-update.md>",
    "textMode": "condense",
    "format": "presentation",
    "numCards": 10,
    "themeId": "'"$GAMMA_THEME_ID"'",
    "textOptions": {
      "tone": "confident, concise",
      "audience": "board of directors",
      "language": "en"
    },
    "exportAs": "pptx"
  }'

# Poll until status is completed or failed; read gammaUrl and exportUrl
curl https://public-api.gamma.app/v1.0/generations/<generationId> \
  -H "X-API-KEY: $GAMMA_API_KEY"
```

{% endtab %}

{% tab title="After (Gamma 5)" %}

```bash
curl -X POST https://public-api.gamma.app/v1.0/agent/generations \
  -H "X-API-KEY: $GAMMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Turn the Q3 update below into a board presentation. Condense it to the key results, risks, and decisions needed; keep every figure exactly as written.\n\n<contents of q3-update.md>",
    "additionalInstructions": "Audience: board of directors. Tone: confident and concise. Write in English. Keep text per slide brief.",
    "format": "presentation",
    "numCards": 10,
    "themeId": "'"$GAMMA_THEME_ID"'",
    "exportAs": "pptx"
  }'

# Poll until status is completed or failed; read gamma.gammaUrl and exportUrl
curl https://public-api.gamma.app/v1.0/agent/generations/<generationId> \
  -H "X-API-KEY: $GAMMA_API_KEY"
```

{% endtab %}
{% endtabs %}

### Complete integration in Python

The full flow, including polling, failure handling, and the download:

{% tabs %}
{% tab title="Before (Classic)" %}

```python
import os, time, requests

BASE = "https://public-api.gamma.app/v1.0"
HEADERS = {"X-API-KEY": os.environ["GAMMA_API_KEY"]}
with open("q3-update.md", encoding="utf-8") as f:
    SOURCE_TEXT = f.read()

resp = requests.post(f"{BASE}/generations", headers=HEADERS, timeout=30, json={
    "inputText": SOURCE_TEXT,
    "textMode": "condense",
    "format": "presentation",
    "numCards": 10,
    "themeId": os.environ["GAMMA_THEME_ID"],
    "textOptions": {
        "tone": "confident, concise",
        "audience": "board of directors",
        "language": "en",
    },
    "exportAs": "pptx",
})
resp.raise_for_status()
generation_id = resp.json()["generationId"]

while True:
    status = requests.get(f"{BASE}/generations/{generation_id}", headers=HEADERS, timeout=30)
    if status.status_code in (429, 503):
        time.sleep(int(status.headers.get("Retry-After", 5)))
        continue
    status.raise_for_status()
    result = status.json()
    if result["status"] == "completed":
        break
    if result["status"] == "failed":
        raise RuntimeError(result.get("error"))
    time.sleep(5)

with requests.get(result["exportUrl"], stream=True, timeout=30) as download:
    download.raise_for_status()
    with open("q3-update.pptx", "wb") as f:
        for chunk in download.iter_content(chunk_size=65536):
            f.write(chunk)
print("Gamma:", result["gammaUrl"])
```

{% endtab %}

{% tab title="After (Gamma 5)" %}

```python
import os, time, requests

BASE = "https://public-api.gamma.app/v1.0"
HEADERS = {"X-API-KEY": os.environ["GAMMA_API_KEY"]}
with open("q3-update.md", encoding="utf-8") as f:
    SOURCE_TEXT = f.read()


def poll(url, deadline_minutes=25):
    deadline = time.monotonic() + deadline_minutes * 60
    while time.monotonic() < deadline:
        resp = requests.get(url, headers=HEADERS, timeout=30)
        if resp.status_code in (429, 503):
            delay = int(resp.headers.get("Retry-After", 5))
            if time.monotonic() + delay > deadline:
                break
            time.sleep(delay)
            continue
        resp.raise_for_status()
        body = resp.json()
        if body["status"] in ("completed", "failed"):
            return body
        time.sleep(5)
    raise TimeoutError(f"Not finished within {deadline_minutes} minutes: {url}")


started = time.monotonic()
resp = requests.post(f"{BASE}/agent/generations", headers=HEADERS, timeout=30, json={
    "prompt": (
        "Turn the Q3 update below into a board presentation. Condense it to the key "
        "results, risks, and decisions needed; keep every figure exactly as written.\n\n"
        + SOURCE_TEXT
    ),
    "additionalInstructions": (
        "Audience: board of directors. Tone: confident and concise. "
        "Write in English. Keep text per slide brief."
    ),
    "format": "presentation",
    "numCards": 10,
    "themeId": os.environ["GAMMA_THEME_ID"],
    "exportAs": "pptx",
})
resp.raise_for_status()
created = resp.json()
generation_id = created["generationId"]
for warning in created["warnings"]:
    print("Warning:", warning["code"], warning["message"])

result = poll(f"{BASE}/agent/generations/{generation_id}")
print(f"Finished in {time.monotonic() - started:.0f}s; credits: {result['credits'].get('deducted')}")
if result["status"] == "failed":
    raise RuntimeError(f"{result['error']['reason']}: {result['error']['message']}")

gamma_id = result["gamma"]["gammaId"]
export_url = result.get("exportUrl")
if export_url is None:
    # The gamma was created but the PPTX export failed (an export_failed warning).
    # Export it again; exports don't charge credits.
    print("Warnings:", [w["code"] for w in result["warnings"]])
    export = requests.post(f"{BASE}/gammas/{gamma_id}/export",
                           headers=HEADERS, timeout=30, json={"exportAs": "pptx"})
    export.raise_for_status()
    export_status = poll(f"{BASE}/exports/{export.json()['exportId']}")
    if export_status["status"] == "failed":
        raise RuntimeError(f"PPTX export failed: {export_status.get('error')}")
    export_url = export_status["exportUrl"]

with requests.get(export_url, stream=True, timeout=30) as download:
    download.raise_for_status()
    with open("q3-update.pptx", "wb") as f:
        for chunk in download.iter_content(chunk_size=65536):
            f.write(chunk)
print("Gamma:", result["gamma"]["gammaUrl"])
```

{% endtab %}
{% endtabs %}

What changed in the code:

* **Request:** `inputText` and `textMode` became a `prompt` that states the job ("condense", "keep every figure") and carries the source text. `textOptions` became plain-language `additionalInstructions`.
* **Polling:** the status path moved under `/agent/`, and the loop has a deadline. Agent jobs usually finish in minutes but can run for up to 20, so keep polling past a few minutes and don't resubmit a job that is still `pending`.
* **Result:** the gamma's id and URL are under `gamma`, `failed` carries `error.reason`, and the code re-exports when `exportUrl` is missing.

Treat `exportUrl` as a secret: anyone with the link can download the file until it expires (about one week). Don't log it.

## Behavior differences

### Settings that become instructions

The agent treats `prompt` and `additionalInstructions` as guidance and does not validate the output against them. Write each Classic setting as a sentence:

| Classic setting                       | Gamma 5 equivalent                                                                                                                                                                   |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `textMode: "generate"` / `"condense"` | Say it in `prompt`: "develop this outline" or "condense this report to the key points". For `"preserve"`, see [Text generation and preservation](#text-generation-and-preservation). |
| `textOptions.tone`, `.audience`       | A sentence in `additionalInstructions`, such as "Audience: new hires. Tone: friendly."                                                                                               |
| `textOptions.language`                | "Write in Japanese." in `additionalInstructions`                                                                                                                                     |
| `textOptions.amount`                  | "Keep text per slide brief" (or detailed) in `additionalInstructions`                                                                                                                |
| `title`                               | Ask for the title in `prompt`; there is no `title` field.                                                                                                                            |
| `folderIds`                           | `folderId` (a single folder id)                                                                                                                                                      |

### Text generation and preservation

Gamma 5 REST generation has no `textMode` field. Describe in `prompt` or `additionalInstructions` whether Gamma should develop an outline, summarize source material, or retain supplied wording.

| What the user wants                       | Recommended handling                                                                                          |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Develop a topic or outline                | Let Gamma write and structure the content.                                                                    |
| Turn a report into a shorter presentation | Pass the original report and the summary goal. Don't have your code or the host rewrite it into slides first. |
| Present finished wording unchanged        | Explicitly request preservation and supply the exact text. Verify the finished output.                        |
| Preserve only certain passages            | Identify those passages separately and state what Gamma may change elsewhere.                                 |

Preserving wording is prompt-directed and isn't automatically validated (see [content and placeholders](/build-with-gamma/brand-template-editing-controls.md#content-and-placeholders)). If your workflow depends on exact text, such as `textMode: "preserve"` today, keep the Classic implementation until you've tested Gamma 5 output against representative inputs.

For approved passages, include the exact text and explicitly prohibit rewriting, shortening, or expanding it. Compare the completed output with the source before distributing it.

{% hint style="info" %}
**On the MCP server, the interface differs.** The MCP [`generate`](/mcp/mcp-tools-reference.md#generate) tool still exposes `textMode` and `cardSplit`:

* Use `preserve` when the user explicitly asks for unchanged wording or supplies finished slide text. Don't select it just because the host has already written a detailed draft.
* A pasted report or notes aren't finished slide copy. Pass the original material plus the user's audience, purpose, and instructions.
* Use `cardSplit: "inputTextBreaks"` only for intentional slide boundaries, not document dividers or breaks the host invented.
* Gamma 5 may resolve bracketed internal notes such as `[TBD]` even with `preserve`; it isn't literal pass-through.
  {% endhint %}

### Controls without a direct equivalent

* `imageOptions` (`source`, `model`, `style`): the agent chooses image sources and models. Describe the image style you want in `additionalInstructions`; you can't pin a model or turn off a source from the request.
* `cardOptions.dimensions` and `cardOptions.headerFooter`: no request field. Use a `templateId` whose layout already has the dimensions, logo, or footer you need.
* `cardSplit: "inputTextBreaks"`: no field. If each section must be its own slide, say so in `prompt`, and check the slide boundaries in the output.
* `format: "webpage"` and multi-page `pages`: not supported on Gamma 5. Keep those integrations on [`POST /generations`](/generations-classic/create-generation.md).

### Slide count and branding

* `numCards` is a soft target. The agent may land a card or two off, and the result is not validated against it. It is still capped by your plan's card limit; a higher value returns `400`.
* On Classic, omitting `themeId` applies the workspace default theme. Gamma 5 has no default: without `themeId` or `templateId` the agent picks a look. Pass `themeId` for your theme, or `templateId` to start from an approved template. Don't send both; the request fails with `400`.
* `sharingOptions` and `folderId` work as before. A setting that a workspace admin restricts is ignored and reported in `warnings` on the create response, so log those.

## What to verify before switching

Run the new integration on a handful of real inputs next to the Classic one and compare:

| Check            | What to look at                                                                                                                                                                                                                                                                                                                                                                  |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Content fidelity | Figures, names, and required sections from the source text appear in the deck, and any wording you asked to keep matches the source exactly. Tighten the `prompt` if the agent condenses or rewrites too much.                                                                                                                                                                   |
| Branding         | The PPTX uses your theme or template: colors, fonts, and logo.                                                                                                                                                                                                                                                                                                                   |
| Slide count      | Close to `numCards`; adjust downstream code that expects an exact count.                                                                                                                                                                                                                                                                                                         |
| Elapsed time     | Time from create to `completed` on your real inputs. Agent jobs can run for up to 20 minutes, so set timeouts and user messaging from what you measure.                                                                                                                                                                                                                          |
| Credits          | `credits.deducted` on the completed or failed response. Cost depends on the work the agent does, so the same input can cost different amounts. The value is best-effort: it can be omitted, or grow if a late charge settles after completion, so for a cost comparison also check usage in [Settings > Billing](https://gamma.app/settings/billing) across several real inputs. |
| Export           | How often a `completed` response arrives without `exportUrl` (an `export_failed` warning), and that your code re-exports or reports the problem when it does.                                                                                                                                                                                                                    |

`quality` (`lite`, `standard`, `max`) changes both output and cost; omitting it uses the API default for your plan. See [Review access and pricing](/get-started/access-and-pricing.md).

## Prompt for your coding agent

Paste this into a coding agent (such as Devin, Claude Code, Codex, or Cursor) running in the repository that holds your Classic integration. Use the copy button on the block.

{% code title="Copy prompt for your coding agent" overflow="wrap" %}

```markdown
Migrate this repository's Gamma Classic text-to-PPTX integration to Gamma 5.

Read https://developers.gamma.app/llms.txt and the current generation, status, polling and pricing references first.

Find the existing request, polling, response parsing and PPTX download code. Explain the required changes, then implement them. Preserve the application's inputs and return format where possible.

Translate content, tone, audience and language requirements into the new request. Identify controls without direct equivalents and any requirements that become prompt guidance. Preserve explicit branding, folder and sharing settings where supported.

Treat existing `textMode: "preserve"` and explicit card boundaries as requirements to review. Don't silently replace them with approximate instructions. Identify what must remain exact, implement an output comparison, and report any behavior difference before recommending the migration.

Update polling and response parsing. Handle failed jobs, warnings and missing exports. Add focused tests for successful PPTX delivery and failure handling.

Report the diff, tests and remaining behavior differences. Keep credentials in environment variables. Run live generation only when authorized.
```

{% endcode %}

## Migrate `from-template` calls

If your integration calls `POST /v1.0/generations/from-template`, move it to `POST /v1.0/agent/generations` with `templateId`. Polling, the `exportUrl` check, and the download step stay the same as in the example above.

```diff
- POST /v1.0/generations/from-template
- { "gammaId": "g_launchdeck1a2b3c", "prompt": "...", "themeId": "...", "exportAs": "pptx" }
+ POST /v1.0/agent/generations
+ { "templateId": "g_launchdeck1a2b3c", "prompt": "Follow this template's structure and style exactly; only replace the content. ...", "exportAs": "pptx" }
```

* **Template id:** pass the same id as `templateId`. Gamma 5 also accepts any gamma in your workspace and official Explore templates (`exploreTemplates[].id` from [`GET /templates/search`](/management/search-templates.md)).
* **How closely to follow it:** Classic keeps the template's structure by default. On Gamma 5 the prompt decides, so say it: "Follow this template's structure and style exactly; only replace the content." Rules that must apply on every run belong in the template's [instructions and locked slides](/build-with-gamma/brand-template-editing-controls.md#template-instructions).
* **Theme:** drop `themeId`. Sending it with `templateId` returns `400`, and the template's own look is the brand. To change the look, save a template with that theme.
* **Title:** there is no `title` field; ask for the title in `prompt`.

See [Generate from approved templates](/build-with-gamma/branded-template-workflow.md) for the full template workflow.

## Related

* [Explore the API](/get-started/understanding-the-api-options.md): Gamma 5 and Classic endpoints side by side
* [POST /agent/generations](/agent-gamma-5/create-agent-generation.md): every request field
* [GET /agent/generations/{generationId}](/agent-gamma-5/get-agent-generation-status.md): pending, completed, and failed responses
* [Review access and pricing](/get-started/access-and-pricing.md): how agent jobs are charged


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://developers.gamma.app/get-started/migrate-from-classic-to-gamma-5.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
