API Overview
The Zandovi public API lets you generate personalized images from your saved templates directly from your own code — e-commerce platforms, email systems, print-on-demand workflows, and automations.
Most calls render: you design and save templates in the app, then call the API to produce images. By default each generate call returns the image bytes directly. Set delivery to link and the same call publishes the render and returns a temporary public URL instead — see Share Links. The API can also author templates from your own code or an AI agent: validate a design, render a preview, then save it — see Authoring Templates.
Base URL
Section titled “Base URL”https://app.zandovi.com/api/v1All endpoints are HTTPS-only and versioned under /api/v1.
What you can do
Section titled “What you can do”| Capability | Endpoint | Notes |
|---|---|---|
| Check your account & plan limits | GET /account | Organization, quota, scopes, and the plan’s limits |
| List your projects | GET /projects | Paginated |
| List templates in a project | GET /projects/{projectId}/templates | Paginated |
| Inspect a template’s variables | GET /templates/{templateId} | Use this to discover what to send |
| Generate an image | POST /templates/{templateId}/generate | Returns binary image data, or a public share link with delivery: "link" |
| Generate in bulk | POST /batch-jobs | One template + many rows → one async job; see Batch Rendering |
| Track batch jobs | GET /batch-jobs, GET /batch-jobs/{jobId} | List and poll job status |
| Inspect per-row outcomes | GET /batch-jobs/{jobId}/items | Paginated: what each submitted row produced, or why it failed |
| Fetch batch results | GET /batch-jobs/{jobId}/result | Download URL or ZIP stream; the archive is kept 30 days |
| Cancel / delete a batch job | POST /batch-jobs/{jobId}/cancel, DELETE /batch-jobs/{jobId} | Cancelling refunds unrendered rows |
| Be told when a batch finishes | callbackUrl on the submit body | Signed POST to your endpoint instead of polling; see Completion Callbacks |
| List your share links | GET /shares | Paginated, newest first |
| Revoke a share link | DELETE /shares/{shareId} | Deletes the published image |
| Manage your image library | GET, POST /images, GET, DELETE /images/{id}, GET /images/{id}/preview | Upload by file or URL and reference as zandovi://images/{id}; free. See Image Library |
| Read the design format | GET /design-reference and sub-routes | Field tables, fonts, icons, presets, examples; free. See Design Reference |
| Validate a design | POST /designs/validate | Free; every violation with a path, code and hint. See Authoring Templates |
| Preview a design | POST /designs/render | One render; returns the image and the render receipt a write needs |
| Create a template | POST /templates | Private template in one of your projects, from a previewed design |
| Read a template’s design | GET /templates/{templateId}?include=canvas | The stored canvasData, to edit and patch back |
| Update / delete a template | PATCH, DELETE /templates/{templateId} | Templates your account created, in the app or through the API; Idempotency-Key honoured |
| Browse a template’s versions | GET /templates/{templateId}/versions, GET .../versions/{version} | The last 10 saved designs, with thumbnails; free. See Version history |
| Restore a version | POST /templates/{templateId}/versions/{version}/restore | Saves the old design as a new version; free, no render |
| Create a project | POST /projects | Private project to hold templates |
To render many images from one template, submit a batch job rather than looping the generate endpoint: one request, one ZIP, and validation before you’re charged. The in-app batch tools drive the same engine from a CSV. Templates can be designed in the app or written as JSON and saved through the authoring endpoints; the MCP server lets an AI assistant do the latter for you.
Authentication
Section titled “Authentication”Requests authenticate with an API key sent in the X-Api-Key header, or an OAuth 2.1 access token sent as an Authorization: Bearer header:
X-Api-Key: your_api_keyAuthorization: Bearer your_access_tokenSend exactly one of the two: a request carrying both is rejected. See Authentication for how to create an API key and how the OAuth flow works.
Request format
Section titled “Request format”- Send
Content-Type: application/jsonfor request bodies. - All timestamps in responses are ISO 8601 in UTC:
2026-06-17T10:00:00Z. - Template and project IDs are UUIDs, e.g.
019463b8-1234-7890-abcd-ef1234567890.
Response format
Section titled “Response format”GETendpoints return JSON.POST /generatereturns the raw image bytes with the matchingContent-Type(image/png,image/jpeg,image/webp, orapplication/pdf) and aContent-Disposition: attachmentheader — write the response body straight to a file or stream it onward.POST /generatewithdelivery: "link"returnsapplication/jsoncarrying the public URL and its expiry instead. See Share Links.POST /batch-jobsis asynchronous — it returns202 Acceptedwith a job ID immediately; poll the job and fetch the ZIP when it completes. See Batch Rendering.POST /designs/renderreturns JSON with the preview image as base64 and arenderReceipt;POST /templatesandPOST /projectsreturn201 Createdwith aLocationheader. See Authoring Templates.
Errors
Section titled “Errors”Error responses use RFC 9457 application/problem+json:
{ "type": "about:blank", "title": "Variable validation failed", "status": 400, "code": "VALIDATION_ERROR", "detail": "Required variable 'discount_code' was not supplied.", "requestId": "3f2b8c1e-7d4a-4b9e-9c2f-5a6d8e1b0c47"}See Errors, quotas & rate limits for the full status-code and error-code reference.
Status codes
Section titled “Status codes”| Code | Meaning |
|---|---|
200 | Success (image or JSON) |
202 | Batch job accepted — poll for the result, or wait for its callback |
400 | Validation error: missing or invalid variables / body, an unknown request property, a plan limit on projects or templates, or both X-Api-Key and Authorization: Bearer sent on the same request |
401 | Missing, invalid, or revoked credential (API key or bearer token) |
402 | The output would exceed your plan’s maxOutputPixels (OUTPUT_SIZE_LIMIT_EXCEEDED; details has outputPixels, maxOutputPixels, plan). Nothing is charged. Lower scale/outputDpi or upgrade |
403 | Share links not available on this plan, the active-link cap is reached, the credential lacks a required scope, or the template or project belongs to another account |
404 | Template, project, share link, or batch job not found / not accessible |
409 | Batch conflict — idempotency key reused, result not ready, or job still active; an authoring write whose Idempotency-Key is still being processed |
410 | The batch result archive passed its 30-day retention window |
422 | A design failed validation, is too large to preview, lacks a valid render receipt, would break the template’s variables, or an Idempotency-Key was reused with a different body — see Authoring Templates; an image supplied for an image variable couldn’t be loaded (IMAGE_VARIABLE_UNREACHABLE) |
429 | Monthly quota or rate limit exceeded |
502 / 503 | Rendering service error / temporarily unavailable |
Quotas & rate limits
Section titled “Quotas & rate limits”Image generation, including design previews, consumes your organization’s monthly render quota; validation, every template or project write and version restores are free. Every generate response carries X-Quota-Limit, X-Quota-Remaining, and X-Quota-Reset headers, and requests are additionally subject to a short-term rate limit. See Errors, quotas & rate limits.
Account & plan limits
Section titled “Account & plan limits”GET /account returns the organization, account and quota behind the presenting credential (API key or bearer token), its effective scopes, plus a limits object with the caps that apply to the current plan:
| Field | Type | Description |
|---|---|---|
maxOutputPixels | number | Largest image size the plan may render, in total pixels (width × height) — see Generating images |
shareRetentionDays | number | null | Days a public share link is kept before it expires; null when the plan doesn’t permit public sharing — see Share Links |
maxActiveShares | number | null | Maximum number of active public share links the organization may hold at once; null when the plan has no limit |
maxBatchRowsPerJob | number | Maximum rows accepted in a single batch job |
Check these before you call the API — for example, to keep a scale/outputDpi combination under maxOutputPixels, or an expiresInDays under shareRetentionDays — instead of discovering the limit from a rejected request.
Versioning
Section titled “Versioning”The API is versioned in the URL (/api/v1). Backwards-incompatible changes ship under a new version; we aim to keep a previous version available for at least 6 months after a new one is released.