Templates & Rendering

Render API Reference

The RenderStack Render API lets you generate images and PDFs programmatically from your templates. All endpoints live under the `/api/v1` base path.

Base URL#

https://renderstack.io/api/v1

Authentication#

All POST render requests require an API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

The GET render endpoint uses a query parameter instead — see GET Render below.

Create and manage API keys from the API Keys page in your dashboard. See API Keys Overview for the full breakdown of key types and security guidance.

Error Format#

All error responses use this structure:

{
  "type": "https://renderstack.io/errors/error-type",
  "title": "Error Title",
  "status": 400,
  "detail": "A human-readable description of the error"
}
StatusTypeDescription
400validation-errorInvalid or missing request parameters
401authentication-errorInvalid, missing, or revoked API key
403forbiddenKey type not permitted for this endpoint, or request origin not in Allowed Hosts
404not-foundTemplate not found
414uri-too-longURL exceeds 8,192 characters (GET endpoint only)
429rate-limitedRate limit exceeded
500server-errorInternal rendering error

Endpoints#

Render Image — Binary#

Renders a template and streams the result back as raw binary data. This is the most common endpoint for server-side integrations — save the response body directly to a file or upload it to storage.

POST /api/v1/renders/sync

Request body:

FieldTypeRequiredDescription
templatestringYesTemplate ID or slug
layersobjectNoDynamic layer overrides (see Layer Overrides)
formatstringNopng, jpeg, or pdf (default: png)
qualitynumberNoJPEG quality 1–100 (default: 90, JPEG only)
widthnumberNoOverride canvas width in pixels
heightnumberNoOverride canvas height in pixels
useAwsbooleanNoUpload rendered output to your configured AWS S3 bucket
filenamestringNoCustom S3 object filename — ignored if useAws is not true

Example:

curl -X POST https://renderstack.io/api/v1/renders/sync \
  -H "Authorization: Bearer rs_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "template": "social-card",
    "layers": {
      "title": { "text": "Welcome to Our Event" },
      "subtitle": { "text": "Join us for an amazing experience" },
      "background_image": { "src": "https://example.com/bg.jpg" },
      "event_date": { "text": "March 15, 2026" }
    },
    "format": "png"
  }' \
  --output social-card.png

Response: 200 with Content-Type: image/png, image/jpeg, or application/pdf. Body is raw binary.

Response headers:

HeaderDescription
X-Render-IdUnique render record ID
X-Render-Duration-MsTime taken to render in milliseconds
X-Render-WarningsJSON array of non-fatal warnings, if any
X-Render-S3-UrlS3 public URL (only when useAws: true and upload succeeds)
X-Render-S3-KeyS3 object key (only when useAws: true)

Render Image — JSON#

Renders a template and returns the result as a base64-encoded JSON response. Useful when you need render metadata alongside the image data, or when you want to process the image in-memory without writing to disk.

POST /api/v1/renders/json

Request body: Identical to the binary endpoint above.

Example:

curl -X POST https://renderstack.io/api/v1/renders/json \
  -H "Authorization: Bearer rs_live_..." \
  -H "Content-Type: application/json" \
  -d '{"template":"social-card","layers":{"title":{"text":"Hello World"}}}'

Success response:

{
  "id": "render_abc123",
  "status": "completed",
  "template": "template_id_here",
  "template_version": 3,
  "created_at": "2026-02-01T14:22:00.000Z",
  "completed_at": "2026-02-01T14:22:00.234Z",
  "duration_ms": 234,
  "output": {
    "data": "data:image/png;base64,iVBORw0KGgo...",
    "mime_type": "image/png",
    "size_bytes": 45320,
    "width": 1200,
    "height": 630
  },
  "warnings": []
}

Response fields:

FieldTypeDescription
idstringUnique render record ID
statusstringcompleted
templatestringTemplate ID
template_versionnumberTemplate version at render time
created_atstringISO 8601 timestamp when render was queued
completed_atstringISO 8601 timestamp when render finished
duration_msnumberRender duration in milliseconds
output.datastringBase64 data URI (e.g., data:image/png;base64,...)
output.mime_typestringimage/png, image/jpeg, or application/pdf
output.size_bytesnumberOutput file size in bytes
output.widthnumberRendered width in pixels
output.heightnumberRendered height in pixels
output.page_countnumberNumber of pages (PDF only)
warningsarrayNon-fatal warning objects (see Warnings)
aws_s3.urlstringS3 public URL (only when useAws: true and upload succeeds)
aws_s3.keystringS3 object key
aws_s3.bucketstringS3 bucket name

Render Image — GET (Dynamic Image URL)#

Renders a template via URL query parameters and returns the result as binary image data. Designed for embedding rendered images directly in HTML, email, or any platform that renders <img> tags. Requires a GET-type API key (rs_get_...) and at least one Allowed Host configured in Settings.

GET /api/v1/render?apiKey=YOUR_GET_KEY&template=TEMPLATE_SLUG

The API key is passed as a query parameter — not in the Authorization header.

Query parameters:

ParameterTypeRequiredDescription
apiKeystringYesGET API key (starts with rs_get_)
templatestringYesTemplate ID or slug
formatstringNopng or jpeg only — PDF not supported (default: png)
qualitynumberNoJPEG quality 1–100 (default: 90)
widthnumberNoOverride canvas width in pixels
heightnumberNoOverride canvas height in pixels
{layer}.{property}stringNoLayer overrides in dot notation (e.g., title.text=Hello)

Layer overrides via dot notation:

Pass layer overrides as layerName.property=value query parameters. Encode spaces as + or %20, and # color values as %23:

?title.text=Hello+World&title.fill=%23ff0000&logo.src=https://example.com/logo.png

Example:

<img src="https://renderstack.io/api/v1/render?apiKey=rs_get_abc123&template=social-card&title.text=Hello+World&subtitle.text=Dynamic+Images" />

Response: 200 with Content-Type: image/png or image/jpeg. Body is raw binary image data.

Response headers:

HeaderDescription
X-CacheHIT (served from cache) or MISS (freshly rendered)
X-Render-IdRender record ID (only on cache MISS)
ETagCache key hash for browser-level caching
Cache-Controlpublic, max-age=604800, immutable

Limits:

  • Maximum URL length: 8,192 characters
  • Maximum canvas dimensions: 8,192 × 8,192 pixels
  • PDF format not supported on this endpoint

Rate limits:

ScopeLimit
Per API key60 requests/minute
Per IP address30 requests/minute
Cache hitsCount as 0.25× toward limits

List Templates#

Returns all templates accessible by the authenticated key.

GET /api/v1/templates

Example:

curl https://renderstack.io/api/v1/templates \
  -H "Authorization: Bearer rs_live_..."

Response:

{
  "data": [
    {
      "id": "template_abc123",
      "name": "Social Card",
      "slug": "social-card",
      "width": 1200,
      "height": 630,
      "version": 3,
      "is_published": true,
      "created_at": "2026-01-15T10:30:00Z",
      "updated_at": "2026-02-01T14:22:00Z"
    }
  ],
  "total": 1
}

Get Template#

Retrieves a single template by ID, including full canvas data and the layer schema.

GET /api/v1/templates/:id

Response fields:

FieldTypeDescription
idstringUnique template ID
namestringDisplay name
slugstringURL-friendly identifier used in render calls
widthnumberCanvas width in pixels
heightnumberCanvas height in pixels
versionnumberCurrent template version number
is_publishedbooleanWhether the template is published
layer_schemaobjectSchema of dynamic layers and their overridable properties
canvas_dataobjectFull element data for all canvas layers
created_atstringISO 8601 creation timestamp
updated_atstringISO 8601 last-modified timestamp

Get Render Record#

Retrieves metadata for a completed render by ID.

GET /api/v1/renders/:id

Example:

curl https://renderstack.io/api/v1/renders/render_abc123 \
  -H "Authorization: Bearer rs_live_..."

Layer Overrides#

The layers object in a render request maps each layer's API Name to the properties you want to override. The API Name is the snake_case identifier set in the template editor (e.g., a layer named "Speaker Name" becomes speaker_name). Only layers marked as Dynamic in the editor can be overridden.

Auto-hide: Layers with Auto visibility mode are completely hidden — no placeholder, no empty box — when you omit them from layers or pass an empty value. Use this to conditionally show or hide elements at render time without modifying the template.

Text layers#

{
  "headline": {
    "text": "Custom text content",
    "fill": "#ff0000",
    "fontSize": 48,
    "fontFamily": "Arial",
    "fontWeight": "bold",
    "textAlign": "center"
  }
}
PropertyTypeDescription
textstringText content to display
fillstringText color (hex, rgb, or named color)
fontSizenumberFont size in pixels
fontFamilystringFont family name
fontWeightstringnormal or bold
fontStylestringnormal or italic
textAlignstringleft, center, or right
boxFillstringBackground fill color for the text element bounding box
boxCornerRadiusnumberCorner radius of the text box
boxPaddingTop / boxPaddingRight / boxPaddingBottom / boxPaddingLeftnumberPadding between box edge and text content

For per-character styling (mixed fonts, bold, italic, color, superscript within a single element), see Rich Text & Inline Styling.

Image layers#

{
  "profile_photo": {
    "src": "https://example.com/photo.jpg",
    "fillMode": "cover"
  }
}
PropertyTypeDescription
srcstringURL of the image to display
fillModestringcover, contain, stretch, or original

For AI-powered face/subject-aware cropping, see Smart Cover.

QR Code layers#

{
  "ticket_qr": {
    "value": "https://example.com/ticket/12345",
    "darkColor": "#1a1a2e",
    "lightColor": "#ffffff",
    "errorCorrectionLevel": "H"
  }
}
PropertyTypeDescription
valuestringData to encode — URL, plain text, vCard, etc.
darkColorstringQR module color (default: #000000)
lightColorstringBackground color, or transparent (default: #ffffff)
errorCorrectionLevelstringL, M (default), Q, or H
marginnumberQuiet zone in modules, 0–10 (default: 2)

Shape layers#

{
  "background_box": {
    "fill": "#3b82f6",
    "stroke": "#1d4ed8",
    "strokeWidth": 2,
    "cornerRadius": 12
  }
}
PropertyTypeDescription
fillstringFill color
strokestringBorder color
strokeWidthnumberBorder thickness in pixels
cornerRadiusnumberCorner radius (rectangles only)

Warnings#

Warnings are returned when a render completes but encountered a non-fatal issue. The image is still produced, but some elements may not appear as expected. Check the X-Render-Warnings response header (binary endpoint) or the warnings array (JSON endpoint).

CodeDescription
IMAGE_LOAD_FAILEDCould not fetch an image from the provided URL
IMAGE_URL_BLOCKEDImage URL was blocked (internal network, SSRF protection)
UNKNOWN_LAYERA key in layers does not match any layer in the template
MISSING_DYNAMIC_LAYERA dynamic layer was not provided — the template default was rendered instead
PRESIGNED_URL_IN_LAYERImage src is a short-lived pre-signed URL (GCS or AWS). Render succeeded but the URL will expire — replace with a stable, permanent URL
S3_UPLOAD_FAILEDFailed to upload the rendered file to AWS S3

Code Examples#

Node.js#

const response = await fetch('https://renderstack.io/api/v1/renders/sync', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer rs_live_...',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    template: 'social-card',
    layers: {
      title: { text: 'Dynamic Title' },
      subtitle: { text: 'Generated with RenderStack' },
    },
  }),
});
const imageBuffer = await response.arrayBuffer();
// Stream to disk, upload to S3, or attach to an email

Python#

import requests

response = requests.post(
    'https://renderstack.io/api/v1/renders/sync',
    headers={
        'Authorization': 'Bearer rs_live_...',
        'Content-Type': 'application/json',
    },
    json={
        'template': 'social-card',
        'layers': {
            'title': {'text': 'Dynamic Title'},
            'subtitle': {'text': 'Generated with RenderStack'},
        },
    },
)

with open('output.png', 'wb') as f:
    f.write(response.content)

PHP#

$ch = curl_init('https://renderstack.io/api/v1/renders/sync');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer rs_live_...',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'template' => 'social-card',
        'layers'   => ['title' => ['text' => 'Dynamic Title']],
    ]),
]);
$image = curl_exec($ch);
curl_close($ch);
file_put_contents('output.png', $image);

cURL#

curl -X POST https://renderstack.io/api/v1/renders/sync \
  -H "Authorization: Bearer rs_live_..." \
  -H "Content-Type: application/json" \
  -d '{"template":"social-card","layers":{"title":{"text":"Hello"}}}' \
  -o output.png

Tip: You can auto-generate a pre-filled curl command from the template editor. Open your template and click the API Payload button (code icon) in the bottom-right corner — it includes your template's slug, canvas dimensions, and all dynamic layer keys already filled in.