Skip to main content
Version: 2.0

Posters API

The Posters API turns a natural-language prompt into a single-canvas, brand-styled poster — a scientific poster, a conference board, a one-page summary — then lets you revise it by describing the change you want and hands you the finished file.

A poster is one canvas, which shapes the whole surface:

  • You choose an orientation and a page size up front.
  • An edit addresses a region of the canvas — "row 2", "the pie chart" — in plain language.
  • Citations render on the canvas, so a reference format (AMA, APA, Vancouver, Prezent Standard) is part of the request.

All three operations stream. You start the work, then read Server-Sent Events for progress and the result.

Full schemas and per-field documentation live in the interactive API Reference.

Authentication

All endpoints require a Bearer token:

Authorization: Bearer YOUR_API_KEY

See Getting Started → Authentication for details.

Endpoint summary

MethodPathDescription
POST/api/v1/posters/generateGenerate a poster
POST/api/v1/posters/editRevise a poster
POST/api/v1/posters/downloadDownload the file
POST/api/v2/streams/sessionsGet a stream URL for a callback_id
GET/api/v1/posters/templatesList available poster templates
GET/api/v1/posters/languagesList supported languages
GET/api/v2/integrations/authConnect a third-party app
GET/api/v2/integrations/auth/statusCheck an app's connection

POST /api/v2/streams/sessions is the shared 2.0 stream-session service — one endpoint serves every artifact type.

How the streaming flow works

Generate and edit both follow the same three steps:

1. POST /api/v1/posters/generate    →  { resData: { callback_id } }
2. POST /api/v2/streams/sessions → { data: { stream_url } }
with that callback_id
3. open stream_url (SSE) → progress events…
terminal event + download_url

The event contract

Every event on the stream has the same shape, so one parser handles the whole stream:

event: status
data: {"status":"inprogress","message":"Composing the poster layout","callback_id":"3f8e7d61-…"}
FieldNotes
statusinprogress while working; then one of success, failed, cancelled
messageHuman-readable step description — safe to show a user verbatim
callback_idThe generation or edit turn this event belongs to
download_urlOnly on a success event. The poster is exported as soon as generation completes, in the export_type the request resolved to, so the terminal event carries a ready-to-fetch URL for that format. Use download to get any other format

The stream closes after the terminal event. Branch on status rather than on the SSE event: name.

Poster progress messages are drawn from a fixed set, in order:

  1. Understanding your prompt
  2. Reading your sources — only when files, links, or text were supplied
  3. Checking for app references — only when the prompt references a connected app
  4. Analyzing the key elements
  5. Composing the poster layout
  6. Selecting visuals and charts
  7. Formatting references — only when a reference_format applies
  8. Finalizing your poster

Steps that do not apply are skipped, so do not treat this as a fixed-length progress bar.

Reconnection, timeouts, and full client code are in Streaming (SSE).

Response envelopes

Errors use the canonical envelope on every endpoint:

{ "success": false, "data": null, "error": { "code": "...", "message": "..." } }

Success shapes are not uniform — each endpoint documents its own:

EndpointSuccess shape
POST /api/v1/posters/generate{ message, resData, error }
POST /api/v1/posters/edit{ message, resData, error }
POST /api/v1/posters/downloadflat top-level fields, including download_url
POST /api/v2/streams/sessions{ success, data }
GET /api/v1/posters/languages{ status, message, data }
GET /api/v1/posters/templates{ success, data }
GET /api/v2/integrations/authone of two shapes — see the endpoint

See Developer Guide → Error codes for the full code catalog.


POST /api/v1/posters/generate — Generate a poster

Starts a generation and returns a callback_id. Nothing else — the poster arrives over the stream.

Request body

FieldTypeRequiredDescription
promptstringyesWhat to generate, in plain language. Describe the layout as well as the content — see Writing a poster prompt.
template_idstringnoBrand template to apply. Takes precedence over settings.template_id; falls back to your key's configured template.
filesarrayno[{ "file_id": "…" }] — files to ground the poster in. Upload first via POST /api/v1/preprocess.
web_linksarraynoURLs for the generator to read.
textstringnoA block of text as source material.
websearchbooleannoLet the generator search the web. Takes precedence over settings.websearch. Default false.
settingsobjectnoPoster settings — see below.

Supplying any of files, web_links, or text makes the request multi-source (internally, multimodal): the generator grounds the poster in what you gave it rather than in its own knowledge. See Grounding a poster in your own content.

Settings

Every key in settings is optional. An omitted key falls back to the default configured on your API key, then to the documented default — so a fully configured key needs no settings object at all.

KeyTypeAccepted values / default
template_idstringAny poster template you can access. Root template_id wins.
orientationstringlandscape, portrait, or square. Default landscape.
sizestringDepends on orientation. Portrait/landscape: a4, a3, a2, letter, tabloid (default a4). Square: small, medium, large, a0_square, xl_square (default medium). See Orientation and size.
languagestringA locale from /api/v1/posters/languages. Default en.
websearchbooleanDefault false. Also settable at the root of the request, which takes precedence.
reference_formatstringama, apa, vancouver, or prezent. Default vancouver. See Reference formats.
add_sources_to_footerbooleanDefault true. Renders the source list in the poster footer — set false to suppress it.
image_libraryobject{ brand_library, prezent_library, ai_images, my_workspace, additional_context }, each a boolean. Omitted keys default to false, except brand_library and prezent_library, which default to true when image_library itself is omitted. company_library and brand_library are the same library — set brand_library.
export_typestringpdf, pptx, jpg, or png. Default pptx.
enable_mcp_contextbooleanDefault false. Pull context from connected apps.

Orientation and size

orientation and size together resolve to a pixel canvas. The generator lays content out for that aspect ratio, so a portrait poster is not a rotated landscape one — the composition differs.

The accepted values of size depend on orientation. Portrait and landscape take paper sizes; square takes its own set of print dimensions. Sending a size from the wrong set is rejected with 422.

portrait and landscape — paper sizes:

sizePortrait (w × h)Landscape (w × h)
a4794 × 11231123 × 794
a31123 × 15871587 × 1123
a21587 × 22452245 × 1587
letter817 × 10541054 × 817
tabloid1054 × 16331633 × 1054

square — sized by print edge length, not paper format:

sizeEdgeCanvas (w × h)
small60 cm2268 × 2268
medium90 cm3402 × 3402
large100 cm3780 × 3780
a0_square84 cm3175 × 3175
xl_square120 cm4535 × 4535

Pixel values are at 96 DPI, and match the dimensions the same selection produces in the Prezent app.

size defaults per orientation: a4 for portrait and landscape, medium for square. So switching to square without naming a size gives you a 90 cm canvas rather than an error.

Values are case-insensitive — A4 and a4 are the same size.

Reference formats

When the poster cites sources — because you supplied files, links, or enabled websearchreference_format controls how the citations are rendered on the canvas.

ValueStyle
amaAmerican Medical Association — superscript numerals, numbered list
apaAmerican Psychological Association — author–date, alphabetical list
vancouverVancouver — bracketed numerals, citation-order list (default)
prezentPrezent Standard — compact inline attribution

ama and vancouver are the conventional choices for scientific and medical posters. The format applies to on-canvas citations regardless of add_sources_to_footer, which only controls whether the full source list is also printed in the footer.

Writing a poster prompt

A poster is read all at once, so the layout matters as much as the content — and the prompt is where you specify it. Describe the regions you want and what goes in each:

Create a poster on cloud misconfiguration as the leading cause of enterprise data breaches. Organise content in 3 horizontal rows. Row 1 covers the problem statement with supporting breach statistics and a pie chart of root causes (misconfiguration, credential compromise, insecure APIs, insider threat). Row 2 presents a comparison table of misconfiguration risk across IaaS, PaaS, and SaaS environments, columns for the most common error, average time-to-detection, and business impact. Row 3 covers preventative controls, a ranked list of top 5 remediations by effectiveness, and an emerging AI-assisted detection framework.

That prompt names the structure (3 rows), the content of each region, and the visual type where it matters (pie chart, comparison table, ranked list). A bare topic — "cloud misconfiguration" — produces a valid poster but leaves every layout decision to the generator, and gives a later edit nothing to address by name.

Naming the regions pays off twice: it also gives you the vocabulary for editing, where "row 2" is how you target part of the canvas.

Grounding a poster in your own content

Any combination of files, web_links, and text can be sent; the generator reads all of them.

Files — upload via POST /api/v1/preprocess and pass the returned file_id. Supported types:

CategoryFormats
Presentations.pptx
Documents.pdf, .docx, .txt
Spreadsheets.xlsx, .csv
Images.png, .jpg, .jpeg

Password-protected and corrupted files are rejected at upload time, not at generation time — check the preprocess response before generating.

Web links — public URLs, read at generation time:

{ "web_links": ["https://example.com/2026-cloud-security-report"] }

Text — paste source material directly:

{ "text": "Internal Q3 findings: …" }

Grounding and websearch are independent: enable both to have the poster built from your sources and supplemented with current public data.

Example

curl -X POST https://api.prezent.ai/api/v1/posters/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Create a poster on cloud misconfiguration as the leading cause of enterprise data breaches. Organise content in 3 horizontal rows. Row 1 covers the problem statement with supporting breach statistics and a pie chart of root causes. Row 2 presents a comparison table of misconfiguration risk across IaaS, PaaS, and SaaS environments. Row 3 covers preventative controls and a ranked list of top 5 remediations by effectiveness.",
"template_id": "your-template-id",
"settings": {
"orientation": "landscape",
"size": "a4",
"language": "en",
"websearch": true,
"reference_format": "vancouver",
"image_library": {
"brand_library": true,
"prezent_library": true,
"ai_images": true
},
"export_type": "pdf"
}
}'

A grounded request — the same poster, built from an uploaded file, a block of pasted text, and live web search:

{
"prompt": "Create a poster on cloud misconfiguration as the leading cause of enterprise data breaches. Organise content in 3 horizontal rows…",
"template_id": "your-template-id",
"files": [{ "file_id": "0efc0f76-4c51-4564-a671-f0ff0c21d23e" }],
"web_links": ["https://example.com/2026-cloud-security-report"],
"text": "Internal Q3 incident review: 61% of findings traced to storage-bucket policy drift…",
"websearch": true,
"settings": {
"orientation": "landscape",
"size": "a3",
"reference_format": "vancouver",
"add_sources_to_footer": true,
"enable_mcp_context": true,
"image_library": {
"brand_library": true,
"prezent_library": true,
"ai_images": true,
"my_workspace": false,
"additional_context": true
}
}
}

A square poster — note that size comes from the square set, not the paper sizes:

{
"prompt": "A square poster on cloud misconfiguration, four quadrants",
"template_id": "your-template-id",
"settings": {
"orientation": "square",
"size": "large"
}
}

Success response (200)

{
"message": "Job submitted successfully",
"resData": {
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91"
},
"error": null
}

The payload is under resData, not data.

callback_id is valid for about 3 hours and is what you pass to streams, edit, and download.

Validation errors (422)

Field-level failures return INVALID_INPUT with error.details as an array of messages, one per failed field:

{
"success": false,
"data": null,
"error": {
"code": "INVALID_INPUT",
"message": "The request contains invalid input.",
"details": [
"prompt is required",
"settings.orientation: 'diagonal' is not supported (accepted values: portrait, landscape, square)",
"settings.size: 'a4' is not valid for orientation 'square' (accepted values: small, medium, large, a0_square, xl_square)"
]
}
}

POST /api/v1/posters/edit — Revise a poster

Applies a natural-language edit to an existing poster.

Edits are conversational: each builds on the last. Pass the callback_id of the most recent turn, and use the new id you get back for the next edit.

The generation must have finished

Editing a callback_id that is still generating returns 400. Wait for the stream's terminal event first.

Only one turn runs at a time — if a previous edit is still in flight, the request is rejected with that reason in error.message.

Request body

FieldTypeRequiredDescription
callback_idstringyesThe poster to edit — the id of the original generation, or of the most recent edit.
promptstringyesThe change to make, in plain language. Name the region you mean.
filesarrayno[{ "file_id": "…" }] — context for this edit.
web_linksarraynoURLs to read as context.
textstringnoA block of text as context.

The poster's settings — template, orientation, size, language, reference format, image sources — are fixed at generation time and carry over unchanged through every edit. Describe what you want in the prompt.

What an edit can change

IntentExample prompt
Change template"Apply the corporate 2026 template"
Replace a visual"Replace the image in row 1 with something from the brand library"
Change a chart"Turn the pie chart of root causes into a horizontal bar chart, sorted descending"
Manage sources"Add the 2026 cloud security report to the sources and switch citations to AMA"
Rewrite content"Shorten every bullet in row 3 to one line"
Change layout"Move the comparison table to row 3 and the remediations to row 2"

Asking for a different orientation or page size reflows the whole canvas. The content is preserved and recomposed for the new aspect ratio; region positions will move. Do it in its own turn rather than combining it with a content edit, so you can see the reflow before changing anything else.

Example

# Edit a region
curl -X POST https://api.prezent.ai/api/v1/posters/edit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91",
"prompt": "In row 2, replace the comparison table with a stacked bar chart and keep the same three columns as series"
}'

# Reflow to a portrait A3 board
curl -X POST https://api.prezent.ai/api/v1/posters/edit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91",
"prompt": "Reflow the poster for a portrait A3 board"
}'

# Add a source and switch citation style
curl -X POST https://api.prezent.ai/api/v1/posters/edit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91",
"prompt": "Cite the added report in row 1 and use AMA style throughout",
"web_links": ["https://example.com/2026-cloud-security-report"]
}'

Success response (200)

{
"message": "Edit submitted successfully",
"resData": {
"callback_id": "8c1d4b92-6f37-4e2a-a95c-1b0e7d3f6a48"
},
"error": null
}

This callback_id is new — not the one you sent. Stream it to watch the edit, and pass it as the callback_id of your next edit to keep building on this version.


POST /api/v1/posters/download — Download the file

Returns the download_url inline. One request, one URL — the poster renders synchronously.

If you ask for the format the generation already produced, that file's URL is returned as-is. Any other format is re-exported from the poster's stored canvas before the URL comes back, so allow up to ~25 seconds for that call.

The poster must have finished generating. Requesting a download while it is still in progress returns 400.

Request body

FieldTypeRequiredDescription
callback_idstringyesThe poster to download.
export_typestringnopptx, pdf, png, or jpg. Defaults to your key's configured format, then pptx.

Each format is a separate export, so the same poster can be downloaded in several — call the endpoint once per export_type.

export_typeResult
pptxA PowerPoint file sized to the canvas — editable downstream. The default.
pdfVector, print-ready at the poster's canvas size. The right choice for printing.
jpgRaster image, smaller file, no transparency. For web and previews.
pngRaster image, lossless, supports transparency. For overlaying or further design work.

Example

curl -X POST https://api.prezent.ai/api/v1/posters/download \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91",
"export_type": "pdf"
}'

Success response (200)

{
"message": "Poster exported successfully",
"status": "success",
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91",
"export_type": "pdf",
"download_url": "https://assets.prezent.ai/protected/…/poster.pdf?callback_id=3f8e7d61-…&token=eyJhbGciOi…&source=prezent-api-framework",
"expires_at": "2026-08-05T12:34:56.000Z"
}

Fields are at the top level, not under data.

download_url carries its own access token, so fetch it as-is and send no Authorization header.

It expires at expires_at (about 5 minutes). Call the endpoint again for a fresh URL — that costs nothing extra when the format is unchanged, as the existing file is reused.

Errors

Statuserror.codeCause
400INVALID_JSONThe body is not valid JSON.
400MISSING_CALLBACK_IDNo callback_id in the body.
400INVALID_DATA_TYPEcallback_id is not a non-empty string, or export_type is not one of the four supported values.
400BAD_REQUESTThe callback_id has no active session (they expire ~3 hours after generation), the poster has not finished generating, or the export itself failed.
500INTERNAL_SERVER_ERRORThe export service was unreachable or returned something unusable.
{
"success": false,
"data": null,
"error": {
"code": "BAD_REQUEST",
"message": "Bad request.",
"details": "This poster is not ready to download yet; wait for generation to complete"
}
}

POST /api/v2/streams/sessions — Get a stream URL

Exchanges a callback_id from poster generate or edit for an authenticated SSE URL. This is the shared 2.0 stream-session endpoint.

Request body

FieldTypeRequiredDescription
callback_idstringyesThe id from poster generate or edit.

Example

curl -X POST https://api.prezent.ai/api/v2/streams/sessions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91" }'

Success response (201)

{
"success": true,
"data": {
"callback_id": "3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91",
"stream_url": "https://stream-api-prod.myprezent.com/v2/streams/a1b2c3?token=eyJhbGciOi...&turn_id=3f8e7d61",
"expires_at": "2026-08-05T12:34:56.000Z"
}
}

The token is in the URL, so send no Authorization header when opening it — browsers' EventSource cannot set headers anyway.

stream_url expires in about 5 minutes. Calling this endpoint again mints a fresh URL, and the stream replays from the start of the turn — so a late reconnect loses nothing.

Errors

Statuserror.codeMeaning
400MISSING_REQUIRED_FIELDcallback_id absent or not a string.
404STREAM_CALLBACK_NOT_FOUNDNo generation found for this id under your key, or its session expired (~3h).

GET /api/v1/posters/templates — List poster templates

Returns the brand templates available for poster generation — the values you pass as template_id.

Always list from this endpoint — a template_id from another surface is not necessarily valid for a poster.

Query parameters

ParameterTypeRequiredDescription
namestringnoCase-insensitive name filter.
sortstringnoSort expression (for example name:asc).
sourcestringnoSource filter (brand vs prezent).
orientationstringnoOnly templates supporting this orientation (landscape, portrait, square).
enabledFeaturestringnoOptional feature flag filter.
limitintegernoItems per page (1–200, default 50). Enables pagination.
cursorstringnoOpaque cursor from a previous response's next_cursor.

Example

curl -s "https://api.prezent.ai/api/v1/posters/templates?orientation=landscape&limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"

Success response (200)

{
"success": true,
"data": {
"items": [
{
"id": "tmpl_corp_2026",
"name": "Corporate 2026",
"code": "CORP26",
"source": "brand",
"orientations": ["landscape", "portrait", "square"]
}
],
"next_cursor": null
}
}

Results are always scoped to the poster feature server-side; the caller cannot override the scoping. See Developer Guide → Pagination.


GET /api/v1/posters/languages — List supported languages

The languages a poster can be generated in. Pass a locale from this list as settings.language; an unsupported value is rejected with 422.

The list is static — cache it rather than calling this before every generation.

Example

curl -s https://api.prezent.ai/api/v1/posters/languages \
-H "Authorization: Bearer YOUR_API_KEY"

Success response (200)

{
"status": "success",
"message": "Supported languages retrieved successfully",
"data": [
{ "language": "Arabic", "locale": "ar" },
{ "language": "Chinese (Simplified)", "locale": "zh" },
{ "language": "English (UK)", "locale": "en-uk" },
{ "language": "English (US)", "locale": "en" },
{ "language": "French", "locale": "fr" },
{ "language": "German", "locale": "de" },
{ "language": "Hindi", "locale": "hi" },
{ "language": "Indonesian", "locale": "id" },
{ "language": "Italian", "locale": "it" },
{ "language": "Japanese", "locale": "ja" },
{ "language": "Korean", "locale": "ko" },
{ "language": "Portuguese (Brazil)", "locale": "pt" },
{ "language": "Spanish", "locale": "es" }
]
}

Right-to-left locales such as ar mirror the poster's region order as well as its text.


GET /api/v2/integrations/auth — Connect an app

Connects a third-party app (Google Drive, Notion, …) to the caller's Prezent account. Once connected, a poster generation can pull context from it by setting settings.enable_mcp_context to true.

The connection is made for the user who owns the API key — there is no parameter to connect an app on someone else's behalf.

Query parameters

ParameterTypeRequiredDescription
mcp_idstringyesIdentifier of the app to connect.

Two response shapes

Which you get is a property of the app, not something you choose. Branch on whether status is present.

Authorization required — send the user to the URL:

{ "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&state=..." }

The URL is single-use and time-limited; request a fresh one rather than storing it. After the user authorizes, confirm with /auth/status.

No authorization needed — already done:

{ "status": "connected", "message": "MCP connection successful" }

Errors

Statuserror.codeMeaning
400MISSING_REQUIRED_FIELDmcp_id not supplied.
404MCP_NOT_FOUNDNo app registered under this mcp_id.
503SERVICE_UNAVAILABLEThe integrations service is temporarily unreachable.

GET /api/v2/integrations/auth/status — Check an app's connection

Whether an app is currently connected for the caller. Use it after sending a user through an authorization URL, and before a poster generation that depends on the app.

Query parameters

ParameterTypeRequiredDescription
mcp_idstringyesIdentifier of the app to check.

Example

curl -s "https://api.prezent.ai/api/v2/integrations/auth/status?mcp_id=google-drive" \
-H "Authorization: Bearer YOUR_API_KEY"

Success response (200)

{ "connected": false }

End-to-end example

Generate a poster, stream it to completion, then download it as a PDF.

import json
import httpx # pip install httpx httpx-sse
from httpx_sse import connect_sse

BASE = "https://api.prezent.ai"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}


def read_stream(stream_url):
"""Read a stream to its terminal event, printing progress as it arrives."""
# The token is in the URL — send no auth header here.
with httpx.Client(timeout=None) as sc:
with connect_sse(sc, "GET", stream_url) as events:
for sse in events.iter_sse():
# The server sends a `:ping` comment every 15s to hold the
# connection open. httpx-sse surfaces those as events with an
# empty `data`, so skip them or json.loads raises.
if not sse.data.strip():
continue
event = json.loads(sse.data)
print(event["status"], "-", event["message"])
if event["status"] == "inprogress":
continue
if event["status"] != "success":
raise RuntimeError(f"{event['status']}: {event['message']}")
return
raise RuntimeError("stream closed without a terminal event")


with httpx.Client(base_url=BASE, headers=HEADERS, timeout=30) as c:
# 1. start the generation
gen = c.post("/api/v1/posters/generate", json={
"prompt": (
"Create a poster on cloud misconfiguration as the leading cause of "
"enterprise data breaches. Organise content in 3 horizontal rows…"
),
"template_id": "your-template-id",
"settings": {
"orientation": "landscape",
"size": "a4",
"reference_format": "vancouver",
"websearch": True,
},
})
gen.raise_for_status()
callback_id = gen.json()["resData"]["callback_id"]

# 2. mint a stream URL, 3. read it to completion
sess = c.post("/api/v2/streams/sessions", json={"callback_id": callback_id})
sess.raise_for_status()
read_stream(sess.json()["data"]["stream_url"])

# 4. ask for the file. A re-export renders while you wait, so allow for it.
dl = c.post(
"/api/v1/posters/download",
json={"callback_id": callback_id, "export_type": "pdf"},
timeout=180,
)
dl.raise_for_status()

print("poster ready:", dl.json()["download_url"])

Errors

Every error uses the canonical envelope. The codes you are most likely to see on this surface:

Statuserror.codeCause
400BAD_REQUEST, INVALID_JSON, MISSING_CALLBACK_ID, MISSING_REQUIRED_FIELD, INVALID_DATA_TYPEMalformed request, unknown callback_id, or poster not ready to edit.
401UNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEYMissing, invalid, or expired key.
404ENDPOINT_NOT_FOUND, STREAM_CALLBACK_NOT_FOUND, MCP_NOT_FOUNDKey not scoped to this path, expired session, or unknown app.
422INVALID_INPUTField validation failed — bad orientation, size, reference_format, or an unsupported language. error.details is an array of messages.
429TOO_MANY_REQUESTS, RATE_LIMIT_EXCEEDED, USAGE_LIMIT_EXCEEDEDGateway throttle, per-category limit, or annual quota.
500INTERNAL_SERVER_ERRORUnexpected server error.
503SERVICE_UNAVAILABLEA downstream service is temporarily unreachable.

Full catalog: Error Reference.

Where to go next

  • Streaming (SSE) — reconnection, timeouts, and production-ready client patterns.
  • File Upload — how to get the file_id values that ground a poster.
  • API Reference — every field, interactively.
  • Rate Limits — the three limit tiers and how to back off.