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/statusGet a turn's status (polling alternative)
GET/api/v1/posters/templatesList available poster templates
GET/api/v1/posters/languagesList supported languages
GET/api/v1/posters/agentsList available agents
GET/api/v1/posters/conferencesList available conferences
GET/api/v2/integrationsList your apps
POST/api/v2/integrations/authConnect or disconnect an 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/v1/posters/agents{ status, log, data }
GET /api/v1/posters/conferences{ status, log, data }
GET /api/v2/integrations{ mcps, count }
POST /api/v2/integrations/authdepends on the app — 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.
agent_codestringnoAgent to generate with — an agent_code from /api/v1/posters/agents. A code that is not available to you is rejected with 422.
conference_codestringnoConference to generate the poster for — a conference_code from /api/v1/posters/conferences. The generator applies that conference's content and design instructions. A code that is not in your list is rejected with 422. See Generating for a conference.
filesarrayno[{ "file_id": "…" }] — files to ground the poster in. Upload first via POST /api/v1/preprocess, then call POST /api/v1/validate and pass the file_id it returns.
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 websearch — reference_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"
}
}

Generating for a conference​

Pass a conference_code from /api/v1/posters/conferences to build the poster for that conference. The generator applies the conference's content and design instructions. It combines with an agent_code, and with any of the fields above:

{
"prompt": "Create a poster on cancer awareness",
"agent_code": "77a488a8-d8f3-4d80-89f1-baf1a7bb39c4",
"conference_code": "5a431fb7-bb8d-47b8-b88c-d4959861af4f",
"settings": {
"orientation": "landscape",
"reference_format": "apa"
}
}

Both codes are checked against your lists before anything is generated. A conference that is unknown, no longer active, or belongs to another industry is rejected with 422. So is an agent that is not in your agent list.

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)"
]
}
}

An agent_code or conference_code that is not available to you is reported the same way:

"details": [
"conference_code: '5a431fb7-bb8d-47b8-b88c-d4959861af4f' is not a valid conference for this user"
]

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.
promptstringyes, unless action_type is sentThe change to make, in plain language. Name the region you mean. Not allowed with action_type.
action_typestringnoApply a specific change with an exact value instead of a prompt — see Actions.
valuestringwith action_typeThe value for action_type.
filesarrayno[{ "file_id": "…" }] — context for this edit. Not allowed with action_type.
web_linksarraynoURLs to read as context. Not allowed with action_type.
textstringnoA block of text as context. Not allowed with action_type.

The poster's settings — 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. The template is the exception: once changed, by a template_change action or by a prompt, the new template carries over to every later edit.

Actions​

A template change can be asked for in a prompt. When you already know the exact template, send action_type and value instead, and the change is applied as given.

action_typevalue
template_changeA template code from GET /api/v1/posters/templates. Re-themes the whole poster.

With action_type, do not send prompt, files, web_links, or text — they are rejected with 422, as are an unknown action_type and a missing or empty value. A template code that is not in your template list is rejected with 400 and error.details set to The selected template is not available.

What an edit can change​

IntentExample prompt
Change template"Apply the corporate 2026 template" — or send a template_change action
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"]
}'

# Switch the poster to another template
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",
"action_type": "template_change",
"value": "CORP26"
}'

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/status — Get a turn's status​

Reads the state of one poster generation or edit turn. This is the polling alternative to the streaming API — same question, answered as a single stateless call instead of a held-open connection.

Query parameters​

ParameterTypeRequiredDescription
callback_idstringyesThe id from poster generate or edit.

Example​

curl -s "https://api.prezent.ai/api/v1/posters/status?callback_id=3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91" \
-H "Authorization: Bearer YOUR_API_KEY"

Success response (200)​

{
"message": "Workflow status polling completed. Your poster is ready to download.",
"status": "success",
"download_url": "https://cdn.prezent.ai/exports/a1b2c3/poster.pdf?token=..."
}

Note this endpoint returns the three fields flat — not wrapped in the { success, data } envelope the other endpoints use.

status is one of:

ValueMeaning
in_progressThe turn is still running, or the file is still being exported.
successThe turn finished and download_url is populated.
failedThe turn is terminal with no artefact. message carries the reason, including a cancellation or a clarifying question.

download_url is an empty string on any status other than success.

Errors​

Statuserror.codeMeaning
400MISSING_REQUIRED_FIELDcallback_id absent or not a string.
400BAD_REQUESTcallback_id is not a valid id, or belongs to a presentation — poll GET /api/v2/autogenerator/status instead.
404STREAM_CALLBACK_NOT_FOUNDNo poster with this id was issued to your API key.

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/v1/posters/agents — List agents​

The poster agents available to the caller — the values you pass as agent_code on generate.

ListContents
default_agentsPrezent's agents for your industry, including any you have customized.
my_agentsAgents you created from scratch.

Example​

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

Success response (200)​

{
"status": "success",
"log": "Agents retrieved successfully",
"data": {
"default_agents": [
{
"agent_code": "scientific_poster",
"agent_name": "Scientific Poster",
"description": "Research posters with methods, results, and conclusions.",
"instructions": "Lay out background, methods, results, and conclusions in reading order."
}
],
"my_agents": [
{
"agent_code": "612a9f7d-c2b8-48ba-8f5a-8acdefade314",
"agent_name": "Conference Board",
"description": "Event posters in our house style.",
"instructions": "Headline across the top, three key takeaways, QR code in the footer."
}
]
}
}

GET /api/v1/posters/conferences — List conferences​

The conferences you can generate posters for, with every detail of each one. Pass a conference_code from this list as conference_code on generate.

The list holds active conferences for your industry: your profile's industry, else your company's. It is sorted by short_name.

Query parameters​

ParameterTypeRequiredDescription
pageintegernoPage number, starting at 1. Default 1. A page past the last returns an empty items.
limitintegernoConferences per page, 1–100. Default 10. A value above 100 is rejected with 400.

This endpoint is always paginated. Without page and limit you get the first 10 conferences, not the whole list. Keep requesting the next page until you have total_count conferences; every page except the last is full.

Example​

# First page
curl -s "https://api.prezent.ai/api/v1/posters/conferences?page=1&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"

# Next page
curl -s "https://api.prezent.ai/api/v1/posters/conferences?page=2&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"

Success response (200)​

{
"status": "success",
"log": "Conferences retrieved successfully",
"data": {
"items": [
{
"conference_code": "5a431fb7-bb8d-47b8-b88c-d4959861af4f",
"num_id": 42,
"short_name": "ASCO",
"full_name": "American Society of Clinical Oncology Annual Meeting",
"therapy_area": "Oncology",
"region": "US",
"website": "https://conferences.asco.org/am/attend",
"start_date": "2026-05-29",
"end_date": "2026-06-02",
"location": "Chicago, IL",
"instructions": "Use a structured abstract layout; include disclosures in the footer.",
"orientation": "landscape",
"height": 48,
"width": 96,
"size_unit": "in",
"min_body_font_pt": 24,
"references_format": "ama",
"industry": "Life Sciences",
"function": "Medical Affairs",
"created_at": "2026-09-16T10:12:44.000Z",
"updated_at": "2026-09-16T10:12:44.000Z"
}
],
"page": 1,
"limit": 10,
"total_count": 37
}
}
FieldDescription
itemsThis page's conferences.
pageThe page returned.
limitThe page size applied.
total_countConferences available to you across all pages.

Optional conference fields such as website, the dates, and the canvas size may be null.

Errors​

Statuserror.codeMeaning
400INVALID_REQUESTlimit is above 100, or page is too large to be valid. error.details.details says which.

GET /api/v2/integrations — List your apps​

The third-party apps your team has enabled, with whether each one is connected for you. Use an app's mcp_id to connect it.

Apps are listed for the user who owns the API key.

Example​

curl -s "https://api.prezent.ai/api/v2/integrations" \
-H "Authorization: Bearer YOUR_API_KEY"

Success response (200)​

{
"mcps": [
{
"mcp_id": "f4623c46-74d3-412e-8213-4f68a9606c97",
"mcp_name": "PubMed",
"description": "Search biomedical literature on PubMed.",
"category": "Life Sciences",
"auth_type": "no_auth",
"sample_prompt": "Build a 4-slide evidence deck. Search PubMed for ...",
"connection_state": "connected"
}
],
"count": 1
}
FieldDescription
mcp_idThe app's ID. Pass it to /integrations/auth.
mcp_nameThe app's display name, e.g. PubMed. May be null.
descriptionWhat the app does. May be null.
categoryApp category, e.g. Life Sciences, Productivity.
auth_typeHow the app connects: dcr / standard (authorization URL), api_key (your API key), no_auth (nothing needed).
sample_promptAn example prompt that uses the app. May be null.
connection_stateconnected or not_connected.

POST /api/v2/integrations/auth — Connect or disconnect an app​

Connects a third-party app to the caller's Prezent account, or disconnects it. 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.

Request body​

FieldTypeRequiredDescription
mcp_idstring (UUID)yesThe app's ID, from GET /api/v2/integrations.
actionstringnoconnect (default) or disconnect.
api_keystringfor api_key appsYour API key for the app.
instance_urlstringfor some appsYour company's MCP URL, for apps that need it (e.g. https://acme.veevavault.com/api/ai/mcp).

GET with query parameters also works for connecting, except for api_key apps — an API key is only accepted in a POST body.

Example​

curl -s -X POST "https://api.prezent.ai/api/v2/integrations/auth" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mcp_id": "6a511689-7e64-42dc-9ca8-cce9bbebd73d",
"api_key": "YOUR_VEEVA_API_KEY",
"instance_url": "https://acme.veevavault.com/api/ai/mcp"
}'

Responses (200)​

Authorization required (dcr / standard apps) — send the user to the URL:

{ "auth_url": "https://accounts.example.com/authorize?client_id=...&state=...", "connected": false }

The URL is single-use and time-limited. After the user authorizes, confirm with /auth/status.

Connected (api_key and no_auth apps, or any app that is already connected):

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

If the app was already connected — whatever its auth_type — you get this same response (no auth_url for dcr / standard apps), the message says so, and the existing connection is kept. To reconnect an app or change its API key, disconnect it first, then connect again.

Disconnected (action: "disconnect"):

{ "status": "disconnected", "message": "MCP disconnected successfully" }

Errors​

Statuserror.codeMeaning
400MISSING_REQUIRED_FIELDmcp_id missing, or the app needs an api_key or instance_url that was not sent. error.details.field names it.
400MCP_NOT_FOUNDNo app with this mcp_id.
400MCP_NOT_CONNECTEDdisconnect on an app that is not connected.
422INVALID_INPUTA field is invalid, e.g. instance_url doesn't match the app's address, or api_key sent to an app that doesn't use one.
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_idstring (UUID)yesThe app's ID.

Example​

curl -s "https://api.prezent.ai/api/v2/integrations/auth/status?mcp_id=f4623c46-74d3-412e-8213-4f68a9606c97" \
-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, poster not ready to edit, or a template_change template that is not available to you.
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, an unsupported language, an agent_code / conference_code not available to you, or an invalid edit action_type / value. 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.