Skip to content

POST /v1/render

Render a document from a template and data. Returns either a download URL or the rendered output inline.

Endpoint:

POST /v1/render

You can render either a saved template (by ID) or an inline template (passed directly in the request).

Option A — Saved template:

{
"templateId": "your-template-id",
"data": { "orderNumber": "ORD-9876", "customer": "Acme Corp" },
"format": "pdf"
}

Option B — Inline template:

{
"template": {
"version": 2,
"units": "in",
"meta": { "name": "Badge" },
"size": { "width": 76.2, "height": 50.8 },
"elements": [
{
"id": "name",
"kind": "text",
"position": { "x": 8, "y": 15 },
"size": { "width": 60, "height": 12 },
"expression": "attendeeName",
"font": { "family": "Arial", "size": 14 },
"color": "#111111"
}
]
},
"data": { "attendeeName": "Jane Smith" },
"format": "png"
}
Field Type Required Description
templateId string One of templateId or template is required ID of a published template. Accepts a template ID, a team slug (e.g., shipping-label), or a library-qualified slug (e.g., carbon:product-2x1). See Template Libraries.
template object One of templateId or template is required Inline template object. See Templates for the full schema.
data object or array Yes Data to bind into the template. An object fills one label (or, on sheet media without slots, is replicated across every cell on the page). An array of objects tiles one row per label cell in reading order across the sheet (and onto additional pages when the array is longer than one sheet). Top-level keys become variables in element expression and visibleExpression fields.
format string Yes Output format: "pdf", "png", "zpl", or "html".
dpi number No Resolution for raster output. Default: 300 for PNG, 203 for ZPL. Ignored for PDF and HTML.
delivery string No "url" (default) returns a JSON response with a download URL. "inline" returns the rendered output directly as the response body.
slots number[] No Optional 1-based sheet positions for partial-sheet printing. Only valid with sheet media templates and formats html, pdf, or png. See Partial-sheet slots below.

When a template has sheet media (an N-up grid such as Avery 2×4), each cell on the page is a numbered slot. Numbering is 1-based and row-major from the top-left:

  • Slot 1 is the top-left cell.
  • On a 2-column grid, slot 2 is the top-right cell; slot 3 is the second row, left cell; and so on through the bottom-right cell.
  • Capacity is columns × rows (for example, 8 on a 2×4 sheet).

Pass slots to print only into chosen positions. Unselected cells render truly blank (no label content). A slots request is always a single page: you cannot request more positions than capacity.

All of the following return HTTP 400 with code INVALID_SLOTS and a specific message:

Rule Detail
Sheet media required The resolved template must have media.type === "sheet".
Format Only "html", "pdf", and "png". Rejected for "zpl" (single-label path).
Values Integers only, unique, each in 1..capacity.
Array data slots.length must equal data.length, and both must be ≤ capacity. A full-capacity permutation is legal.
Object data 1 ≤ slots.length ≤ capacity. The same object is replicated into every listed slot.
Omitted If slots is omitted, behaviour is unchanged from today (full-sheet fill / multi-page tiling).

Two data rows placed in physical positions 4 and 6 (leaving the rest blank):

{
"templateId": "avery-22890-labels",
"data": [
{ "name": "A" },
{ "name": "B" }
],
"slots": [4, 6],
"format": "pdf"
}

Row data[i] is printed into slots[i]. Order in the array is meaningful — you may permute slots deliberately.

Example — single object into selected slots

Section titled “Example — single object into selected slots”

One object copied into slots 1, 3, and 5 only:

{
"templateId": "avery-22890-labels",
"data": { "name": "Jane Smith", "role": "Guest" },
"slots": [1, 3, 5],
"format": "pdf"
}

Without slots, the same object is still replicated across every cell on the sheet (existing behaviour).

Status: 200 OK

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "complete",
"format": "pdf",
"url": "https://api.binderypress.dev/v1/render-outputs/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sizeBytes": 12345,
"renderTimeMs": 450
}
Field Type Description
id string Unique render job ID (UUID).
status string "complete".
format string The output format.
url string Download URL. Valid for 7 days.
sizeBytes number Output file size in bytes.
renderTimeMs number Time spent rendering in milliseconds.

The response also includes rate limit headers.

Status: 200 OK

The response body contains the rendered document directly. The Content-Type header matches the format:

Format Content-Type
pdf application/pdf
png image/png
zpl text/plain
html text/html
Terminal window
curl -X POST https://api.binderypress.dev/v1/render \
-H "Authorization: Bearer bp_sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "shipping-label",
"data": {
"orderNumber": "ORD-9876",
"customer": "Acme Corp",
"items": [
{ "name": "Widget A", "qty": 10 },
{ "name": "Widget B", "qty": 5 }
]
},
"format": "pdf"
}'
Terminal window
curl -X POST https://api.binderypress.dev/v1/render \
-H "Authorization: Bearer bp_sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": {
"version": 2,
"units": "in",
"meta": { "name": "Badge" },
"size": { "width": 76.2, "height": 50.8 },
"elements": [
{
"id": "name",
"kind": "text",
"position": { "x": 8, "y": 15 },
"size": { "width": 60, "height": 14 },
"expression": "attendeeName",
"font": { "family": "Arial", "size": 20, "weight": "bold" },
"color": "#111111"
}
]
},
"data": { "attendeeName": "Jane Smith" },
"format": "png",
"dpi": 150
}'

Render ZPL for label printer (inline delivery)

Section titled “Render ZPL for label printer (inline delivery)”
Terminal window
curl -X POST https://api.binderypress.dev/v1/render \
-H "Authorization: Bearer bp_sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "label-template-id",
"data": { "sku": "WIDGET-001", "quantity": 50 },
"format": "zpl",
"dpi": 203,
"delivery": "inline"
}' \
-o label.zpl
Terminal window
curl -X POST https://api.binderypress.dev/v1/render \
-H "Authorization: Bearer bp_sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "carbon:product-2x1",
"data": { "sku": "WIDGET-001", "name": "Widget A" },
"format": "pdf"
}'

Library templates use the librarySlug:templateSlug format. See Template Libraries for details.

Schema validation errors use details.issues, an array of objects with path and message fields.

Status Code Cause
400 BAD_REQUEST Missing required fields or invalid format.
400 V1_SCHEMA The inline template uses the legacy schema; this endpoint accepts schema v2 only.
400 INVALID_TEMPLATE The inline template failed schema v2 validation. Check details.issues.
401 AUTH_REQUIRED Missing or invalid API key.
404 NOT_FOUND Template ID not found (when using templateId).
413 PAYLOAD_TOO_LARGE Request body exceeds 10 MB (1 MB for demo keys).
429 RATE_LIMITED Too many requests. Retry after the Retry-After period.
429 QUOTA_EXCEEDED Monthly quota exceeded (hard-capped plans only).
500 STORED_TEMPLATE_INVALID The saved template failed schema v2 validation.
502 RENDER_ERROR Rendering failed.