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
| Method | Path | Description |
|---|---|---|
POST | /api/v1/posters/generate | Generate a poster |
POST | /api/v1/posters/edit | Revise a poster |
POST | /api/v1/posters/download | Download the file |
POST | /api/v2/streams/sessions | Get a stream URL for a callback_id |
GET | /api/v1/posters/templates | List available poster templates |
GET | /api/v1/posters/languages | List supported languages |
GET | /api/v2/integrations/auth | Connect a third-party app |
GET | /api/v2/integrations/auth/status | Check 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-…"}
| Field | Notes |
|---|---|
status | inprogress while working; then one of success, failed, cancelled |
message | Human-readable step description — safe to show a user verbatim |
callback_id | The generation or edit turn this event belongs to |
download_url | Only 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:
- Understanding your prompt
- Reading your sources — only when files, links, or text were supplied
- Checking for app references — only when the prompt references a connected app
- Analyzing the key elements
- Composing the poster layout
- Selecting visuals and charts
- Formatting references — only when a
reference_formatapplies - 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:
| Endpoint | Success shape |
|---|---|
POST /api/v1/posters/generate | { message, resData, error } |
POST /api/v1/posters/edit | { message, resData, error } |
POST /api/v1/posters/download | flat 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/auth | one 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
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | yes | What to generate, in plain language. Describe the layout as well as the content — see Writing a poster prompt. |
template_id | string | no | Brand template to apply. Takes precedence over settings.template_id; falls back to your key's configured template. |
files | array | no | [{ "file_id": "…" }] — files to ground the poster in. Upload first via POST /api/v1/preprocess. |
web_links | array | no | URLs for the generator to read. |
text | string | no | A block of text as source material. |
websearch | boolean | no | Let the generator search the web. Takes precedence over settings.websearch. Default false. |
settings | object | no | Poster 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.
| Key | Type | Accepted values / default |
|---|---|---|
template_id | string | Any poster template you can access. Root template_id wins. |
orientation | string | landscape, portrait, or square. Default landscape. |
size | string | Depends 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. |
language | string | A locale from /api/v1/posters/languages. Default en. |
websearch | boolean | Default false. Also settable at the root of the request, which takes precedence. |
reference_format | string | ama, apa, vancouver, or prezent. Default vancouver. See Reference formats. |
add_sources_to_footer | boolean | Default true. Renders the source list in the poster footer — set false to suppress it. |
image_library | object | { 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_type | string | pdf, pptx, jpg, or png. Default pptx. |
enable_mcp_context | boolean | Default 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:
size | Portrait (w × h) | Landscape (w × h) |
|---|---|---|
a4 | 794 × 1123 | 1123 × 794 |
a3 | 1123 × 1587 | 1587 × 1123 |
a2 | 1587 × 2245 | 2245 × 1587 |
letter | 817 × 1054 | 1054 × 817 |
tabloid | 1054 × 1633 | 1633 × 1054 |
square — sized by print edge length, not paper format:
size | Edge | Canvas (w × h) |
|---|---|---|
small | 60 cm | 2268 × 2268 |
medium | 90 cm | 3402 × 3402 |
large | 100 cm | 3780 × 3780 |
a0_square | 84 cm | 3175 × 3175 |
xl_square | 120 cm | 4535 × 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 websearch — reference_format controls how the citations are
rendered on the canvas.
| Value | Style |
|---|---|
ama | American Medical Association — superscript numerals, numbered list |
apa | American Psychological Association — author–date, alphabetical list |
vancouver | Vancouver — bracketed numerals, citation-order list (default) |
prezent | Prezent 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:
| Category | Formats |
|---|---|
| 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
- Python
- Node.js
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"
}
}'
import requests
resp = requests.post(
"https://api.prezent.ai/api/v1/posters/generate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"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 breach statistics and a pie "
"chart of root causes. Row 2 presents a comparison table of risk "
"across IaaS, PaaS, and SaaS. Row 3 covers preventative controls."
),
"template_id": "your-template-id",
"settings": {
"orientation": "landscape",
"size": "a4",
"language": "en",
"websearch": True,
"reference_format": "vancouver",
"export_type": "pdf",
},
},
)
resp.raise_for_status()
callback_id = resp.json()["resData"]["callback_id"]
const res = await fetch('https://api.prezent.ai/api/v1/posters/generate', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
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 breach statistics and a pie ' +
'chart of root causes. Row 2 presents a comparison table of risk ' +
'across IaaS, PaaS, and SaaS. Row 3 covers preventative controls.',
template_id: 'your-template-id',
settings: {
orientation: 'landscape',
size: 'a4',
language: 'en',
websearch: true,
reference_format: 'vancouver',
export_type: 'pdf',
},
}),
});
const { resData } = await res.json();
const callbackId = resData.callback_id;
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.
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
| Field | Type | Required | Description |
|---|---|---|---|
callback_id | string | yes | The poster to edit — the id of the original generation, or of the most recent edit. |
prompt | string | yes | The change to make, in plain language. Name the region you mean. |
files | array | no | [{ "file_id": "…" }] — context for this edit. |
web_links | array | no | URLs to read as context. |
text | string | no | A 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
| Intent | Example 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
| Field | Type | Required | Description |
|---|---|---|---|
callback_id | string | yes | The poster to download. |
export_type | string | no | pptx, 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_type | Result |
|---|---|
pptx | A PowerPoint file sized to the canvas — editable downstream. The default. |
pdf | Vector, print-ready at the poster's canvas size. The right choice for printing. |
jpg | Raster image, smaller file, no transparency. For web and previews. |
png | Raster 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
| Status | error.code | Cause |
|---|---|---|
400 | INVALID_JSON | The body is not valid JSON. |
400 | MISSING_CALLBACK_ID | No callback_id in the body. |
400 | INVALID_DATA_TYPE | callback_id is not a non-empty string, or export_type is not one of the four supported values. |
400 | BAD_REQUEST | The callback_id has no active session (they expire ~3 hours after generation), the poster has not finished generating, or the export itself failed. |
500 | INTERNAL_SERVER_ERROR | The 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
| Field | Type | Required | Description |
|---|---|---|---|
callback_id | string | yes | The 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
| Status | error.code | Meaning |
|---|---|---|
400 | MISSING_REQUIRED_FIELD | callback_id absent or not a string. |
404 | STREAM_CALLBACK_NOT_FOUND | No 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
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | no | Case-insensitive name filter. |
sort | string | no | Sort expression (for example name:asc). |
source | string | no | Source filter (brand vs prezent). |
orientation | string | no | Only templates supporting this orientation (landscape, portrait, square). |
enabledFeature | string | no | Optional feature flag filter. |
limit | integer | no | Items per page (1–200, default 50). Enables pagination. |
cursor | string | no | Opaque 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
| Parameter | Type | Required | Description |
|---|---|---|---|
mcp_id | string | yes | Identifier 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
| Status | error.code | Meaning |
|---|---|---|
400 | MISSING_REQUIRED_FIELD | mcp_id not supplied. |
404 | MCP_NOT_FOUND | No app registered under this mcp_id. |
503 | SERVICE_UNAVAILABLE | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
mcp_id | string | yes | Identifier 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.
- Python
- Node.js
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"])
import { EventSource } from 'eventsource'; // npm install eventsource
const BASE = 'https://api.prezent.ai';
const HEADERS = {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
};
const post = async (path, body) => {
const res = await fetch(`${BASE}${path}`, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`${path} → ${res.status} ${await res.text()}`);
return res.json();
};
// Read a stream to its terminal event, logging progress as it arrives.
const readStream = (streamUrl) =>
new Promise((resolve, reject) => {
// The token is in the URL — no Authorization header here.
const es = new EventSource(streamUrl);
es.onmessage = (e) => {
const event = JSON.parse(e.data);
console.log(event.status, '-', event.message);
if (event.status === 'inprogress') return;
es.close();
if (event.status === 'success') resolve();
else reject(new Error(`${event.status}: ${event.message}`));
};
es.onerror = () => { es.close(); reject(new Error('stream failed')); };
});
// 1. start
const { resData } = await post('/api/v1/posters/generate', {
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,
},
});
const callbackId = resData.callback_id;
// 2 + 3. stream to completion
const { data } = await post('/api/v2/streams/sessions', { callback_id: callbackId });
await readStream(data.stream_url);
// 4. ask for the file — the URL comes back inline
const dl = await post('/api/v1/posters/download', {
callback_id: callbackId,
export_type: 'pdf',
});
console.log('poster ready:', dl.download_url);
Errors
Every error uses the canonical envelope. The codes you are most likely to see on this surface:
| Status | error.code | Cause |
|---|---|---|
400 | BAD_REQUEST, INVALID_JSON, MISSING_CALLBACK_ID, MISSING_REQUIRED_FIELD, INVALID_DATA_TYPE | Malformed request, unknown callback_id, or poster not ready to edit. |
401 | UNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEY | Missing, invalid, or expired key. |
404 | ENDPOINT_NOT_FOUND, STREAM_CALLBACK_NOT_FOUND, MCP_NOT_FOUND | Key not scoped to this path, expired session, or unknown app. |
422 | INVALID_INPUT | Field validation failed — bad orientation, size, reference_format, or an unsupported language. error.details is an array of messages. |
429 | TOO_MANY_REQUESTS, RATE_LIMIT_EXCEEDED, USAGE_LIMIT_EXCEEDED | Gateway throttle, per-category limit, or annual quota. |
500 | INTERNAL_SERVER_ERROR | Unexpected server error. |
503 | SERVICE_UNAVAILABLE | A 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_idvalues that ground a poster. - API Reference — every field, interactively.
- Rate Limits — the three limit tiers and how to back off.