API Keys & Integration

Template Integration Guide (for Developers)

This document is a technical reference for engineers building applications that generate images or PDFs dynamically using RenderStack templates. It covers how templates are structured, how to discover


Table of Contents#

  1. Core Concepts
  2. Discovering a Template's Fields
  3. Render API
  4. The layers Object
  5. Element Types and Overridable Properties
  6. Auto-Visibility Behavior
  7. Pinning and Anchored Layouts
  8. Output Format and Quality
  9. Response Headers and Warnings
  10. Plan Feature Gates
  11. Common Patterns

Core Concepts#

A template is a pixel-precise canvas design. It contains one or more layers (elements). Some layers are static — they always render exactly as designed. Others are marked dynamic — their content can be overridden at render time by your application.

Each dynamic layer has an API Name (a stable, snake_case identifier like event_title or speaker_photo). When calling the render API, you supply a layers object keyed by these API Names. The template designer controls which properties of each layer are dynamic.

The render engine resolves all layout — including pinning, anchoring, and repeater expansion — server-side. Your application only needs to supply the data; you never need to compute positions.


Discovering a Template's Fields#

Before building an integration, fetch the template's metadata to see what fields are available and what types they expect.

List all templates#

GET /api/v1/templates
Authorization: Bearer rs_live_YOUR_KEY

Get a specific template#

GET /api/v1/templates/{id_or_slug}
Authorization: Bearer rs_live_YOUR_KEY

Both endpoints return a layer_schema object that describes every dynamic field:

{
  "id": "tmpl_abc123",
  "name": "Event Badge",
  "slug": "event-badge",
  "width": 800,
  "height": 500,
  "output_format": "png",
  "layer_schema": {
    "attendee_name": { "type": "text" },
    "job_title":     { "type": "text" },
    "company":       { "type": "text" },
    "headshot":      { "type": "image" },
    "qr_code":       { "type": "qrcode" },
    "line_items":    {
      "type": "repeater",
      "items": {
        "item_name":  { "type": "text" },
        "item_price": { "type": "text" },
        "item_image": { "type": "image" }
      }
    }
  }
}

The keys in layer_schema are the exact strings you use as keys in your layers payload. The type tells you what kind of override value to send (see Element Types).


Render API#

Authentication#

Key TypePrefixUsed For
Live keyrs_live_POST renders (server-to-server)
Master keyrs_master_POST renders with elevated access
GET keyrs_get_Embeddable GET URLs only
Read-only keyrs_ro_Fetching template metadata only

For POST requests, pass the key as a Bearer token:

Authorization: Bearer rs_live_YOUR_KEY

For GET render URLs, pass the key as a query parameter (apiKey=rs_get_YOUR_KEY). GET keys are additionally restricted to a list of Allowed Hosts configured in the dashboard — only requests originating from those domains will be served.


POST — Synchronous Render#

Returns the rendered image or PDF binary directly in the response body.

POST /api/v1/renders/sync
Authorization: Bearer rs_live_YOUR_KEY
Content-Type: application/json

Request body:

{
  "template": "event-badge",
  "layers": {
    "attendee_name": { "text": "Sarah Chen" },
    "job_title":     { "text": "Senior Engineer" },
    "company":       { "text": "Acme Corp" },
    "headshot":      { "src": "https://cdn.example.com/sarah.jpg" },
    "qr_code":       { "value": "https://checkin.example.com/ATT-4829" }
  },
  "format": "png",
  "quality": 90
}
FieldTypeRequiredDescription
templatestringYesTemplate ID or slug
layersobjectNoLayer overrides keyed by API Name
formatstringNo"png", "jpeg", or "pdf". Defaults to template setting.
qualityintegerNo1–100. Defaults to template setting (usually 90).
widthintegerNoOverride the template's width in pixels
heightintegerNoOverride the template's height in pixels
useAwsbooleanNoIf true, uploads the result to your connected S3 bucket
filenamestringNoFilename hint used when uploading to S3
sizesarrayNoPDF only. Array of { width, height } objects for multi-page output

Response: Binary image/PDF with Content-Type: image/png, image/jpeg, or application/pdf.


POST — JSON Response Render#

Returns a JSON body with a URL to the rendered result instead of raw binary.

POST /api/v1/renders/json
Authorization: Bearer rs_live_YOUR_KEY
Content-Type: application/json

Request body is identical to /renders/sync. Response:

{
  "renderId": "rnd_xyz",
  "url": "https://cdn.renderstack.io/renders/rnd_xyz.png",
  "status": "completed",
  "durationMs": 143
}

GET — Embeddable URL Render#

Renders an image on demand from a URL. Designed for use in <img> tags, email Open Graph tags, or any context where a URL is required rather than a programmatic call.

GET /api/v1/render?apiKey=rs_get_KEY&template=SLUG&layer.property=value

Reserved query parameters:

ParameterDescription
apiKeyYour GET-type API key (rs_get_...)
templateTemplate ID or slug
formatpng, jpeg
quality1–100
widthOverride width
heightOverride height

Layer overrides use dot notation: {apiName}.{property}=value. For example:

?template=event-badge
&attendee_name.text=Sarah+Chen
&job_title.text=Senior+Engineer
&headshot.src=https%3A%2F%2Fcdn.example.com%2Fsarah.jpg
&qr_code.value=https%3A%2F%2Fcheckin.example.com%2FATT-4829

GET responses are cached aggressively using ETag and Cache-Control headers. Identical parameter combinations will serve from cache. If your data changes frequently, append a cache-busting parameter (e.g., a version or timestamp not used by the render engine).


The layers Object#

The layers object maps each dynamic layer's API Name to an object of property overrides. You only need to include layers you want to change — omitted layers render with their template defaults.

{
  "layers": {
    "api_name_of_layer": {
      "property_to_override": "new_value"
    }
  }
}

If you supply a layer name that does not exist in the template, the render still succeeds and a warning is returned in the X-Render-Warnings response header (see Response Headers).


Element Types and Overridable Properties#

Text Elements#

layer_schema type: "text"

Override any combination of these properties:

PropertyTypeDescription
textstringPlain text content
richTextstringHTML-like rich text (takes priority over text)
textRunsarrayArray of TextRun objects for per-word/character styling (see below)
fontSizenumberSize in pixels
fontFamilystringFont name (must be available in your org's font library or web-safe)
fontWeightstring"normal", "bold", "100""900"
fontStylestring"normal", "italic"
fillstringText color as hex ("#ffffff") or CSS color
textAlignstring"left", "center", "right"
verticalAlignstring"top", "middle", "bottom"
letterSpacingnumberExtra spacing between characters (pixels)
lineSpacingnumberExtra spacing between lines (pixels)
textStrategystring"normal", "auto-size" (shrinks font to fit), "truncate", "clip"
backgroundColorstringInline highlight color drawn directly behind the text characters
backgroundPaddingnumberPadding around the inline text background
underlinebooleanUnderline the text
linethroughbooleanStrikethrough the text
boxFillstringBackground fill color for the entire text element bounding box (renders behind text like a shape)
boxFillOpacitynumberFill opacity 0–1
boxStrokestringBorder color for the text element box
boxStrokeWidthnumberBorder thickness value
boxStrokeWidthUnitstringUnit for border thickness: "px" (default) or "%" (percentage of element's smallest dimension)
boxStrokeWidthMinnumberMinimum border thickness in px when using % unit
boxStrokeWidthMaxnumberMaximum border thickness in px when using % unit
boxStrokeOpacitynumberBorder opacity 0–1
boxStrokeAlignstring"inner", "center" (default), "outer"
boxCornerRadiusnumberCorner radius value for the text element box
boxCornerRadiusUnitstringUnit for corner radius: "px" (default) or "%" (percentage of element's smallest dimension)
boxCornerRadiusMinnumberMinimum corner radius in px when using % unit
boxCornerRadiusMaxnumberMaximum corner radius in px when using % unit

Example:

"event_title": {
  "text": "Tech Summit 2026",
  "fontSize": 48,
  "fill": "#1a1a2e",
  "textAlign": "center"
}

Rich Text with textRuns#

For per-word or per-segment styling within a single layer, use textRuns. Each run is a segment with its own style:

"speaker_bio": {
  "textRuns": [
    { "text": "Jane Smith", "font": "Arial", "size": 24, "weight": "bold", "color": "#0f172a" },
    { "text": " — Principal Engineer at Acme", "font": "Arial", "size": 18, "color": "#64748b" }
  ]
}

TextRun fields: text, font, size, weight ("normal" | "bold"), style ("normal" | "italic"), color, underline (boolean), linethrough (boolean).


Image Elements#

layer_schema type: "image"

PropertyTypeDescription
srcstringImage URL (HTTPS) or a data URI
fillModestringHow the image fills its frame (see below)
imageAnchorstringAlignment when image doesn't fill the frame: "top-left", "top-center", "top-right", "center-left", "center-center", "center-right", "bottom-left", "bottom-center", "bottom-right"
cornerRadiusnumberRounds the image frame corners (pixels)
strokestringBorder color
strokeWidthnumberBorder thickness (pixels)
strokeAlignstring"inside", "outside", "center"

Fill modes:

ModeDescription
"cover"Scales image to fill the frame, cropping if needed. Default.
"contain"Scales image to fit entirely inside the frame, no cropping.
"stretch"Stretches image to exactly match the frame dimensions.
"original"Renders image at its native resolution, no scaling.
"smart-cover"Like cover, but detects the subject's focal point automatically and crops around it. Best for headshots and product photos.

Example:

"speaker_photo": {
  "src": "https://cdn.example.com/speakers/jane-smith.jpg",
  "fillMode": "smart-cover",
  "cornerRadius": 50
}

QR Code Elements#

layer_schema type: "qrcode"

Plan requirement: QR code elements require a Pro plan or higher.

PropertyTypeDescription
valuestringThe data to encode (URL, plain text, vCard, etc.)
darkColorstringForeground color (hex). Default "#000000"
lightColorstringBackground color (hex). Default "#ffffff"
errorCorrectionLevelstring"L" (7%), "M" (15%), "Q" (25%), "H" (30%). Higher = more recoverable if the code is partially obscured. Default "M"
marginnumberQuiet zone padding around the code
cornerRadiusnumberRounds the QR code container

Example:

"check_in_qr": {
  "value": "https://events.example.com/check-in?attendee=ATT-4829&event=summit-2026",
  "darkColor": "#1a1a2e",
  "lightColor": "#ffffff",
  "errorCorrectionLevel": "H"
}

Repeater Elements#

layer_schema type: "repeater"

Plan requirement: Repeater elements require a Business or Enterprise plan.

A repeater is a container that clones a row template for each item in a data array. This is the right element for lists of variable length: event schedules, leaderboards, invoice line items, product grids, etc.

The template designer defines the repeater's row template (a fixed set of child layers) and sets the direction, spacing, and maximum items. At render time, you supply an array of objects — one per row.

How to send data:

The key in layers is the repeater's API Name. The value must be an array of objects. Each object's keys map to the API Names of the child layers inside one row:

"layers": {
  "schedule_items": [
    {
      "session_title": { "text": "Opening Keynote" },
      "session_time":  { "text": "9:00 AM – 10:00 AM" },
      "speaker_name":  { "text": "Jane Smith" },
      "session_image": { "src": "https://cdn.example.com/keynote.jpg" }
    },
    {
      "session_title": { "text": "Deep Dive: AI in Production" },
      "session_time":  { "text": "10:15 AM – 11:15 AM" },
      "speaker_name":  { "text": "Marcus Reyes" },
      "session_image": { "src": "https://cdn.example.com/ai-session.jpg" }
    },
    {
      "session_title": { "text": "Closing Panel" },
      "session_time":  { "text": "4:00 PM – 5:00 PM" },
      "speaker_name":  { "text": "All Speakers" },
      "session_image": { "src": "https://cdn.example.com/panel.jpg" }
    }
  ]
}

Child layer overrides follow the same property structure as their respective element types (text, image, etc.).

Repeater layout properties (these are set by the template designer and applied automatically, but can be overridden at render time):

PropertyTypeDescription
directionstring"vertical" (rows stacked), "horizontal" (side by side), "grid" (multi-column)
rowGapnumberVertical space between rows (pixels)
columnGapnumberHorizontal space between columns in grid mode (pixels)
columnsnumberNumber of columns in grid mode
maxItemsnumberCap the number of rendered rows (items beyond this are silently dropped)

What happens if you send more items than maxItems? Items beyond the cap are silently dropped. No error is returned.

What happens if the array is empty? The repeater renders nothing (zero height/width contribution) unless the template designer enabled the fallbackEmptyVisible option, in which case the row template renders once with all default values.


Shape Elements#

layer_schema types: "rect", "ellipse", "line"

Shapes are usually static design elements (backgrounds, dividers, badges), but when marked dynamic they support:

PropertyTypeDescription
fillstringFill color (hex or CSS)
fillOpacitynumberFill opacity 0–1
strokestringBorder/line color
strokeWidthnumberBorder thickness (pixels)
strokeOpacitynumberBorder opacity 0–1
strokeAlignstring"inside", "outside", "center"
cornerRadiusnumberCorner rounding, rect only (pixels)

Example — dynamically color-code an event track badge:

"track_color_bar": {
  "fill": "#3b82f6"
}

Auto-Visibility Behavior#

Layers configured with auto-visibility automatically hide themselves during rendering if their required content is absent. This prevents broken placeholders from appearing in your output.

Auto-hide rules by element type:

TypeHides when…
Any dynamic layerNo data is provided for it in layers at all
imagesrc is missing or empty
texttext, richText, and textRuns are all missing or empty
qrcodevalue is missing or empty

Practical use: If your events application sometimes has a speaker photo and sometimes does not, mark the headshot image layer as auto-visible. When you don't supply a src, the image frame won't appear in the rendered output. You don't need to send a visibility toggle — omitting the field is enough.

To explicitly force a layer to be visible or hidden regardless of content:

"optional_badge": {
  "visible": true
}

or

"optional_badge": {
  "visible": false
}

Pinning and Anchored Layouts#

Many templates use pinning to anchor elements relative to other elements. For example, a subtitle might be pinned to always appear 12px below the title, or a footer might be pinned to the bottom edge of the canvas.

You do not need to do anything for pinning to work. The render engine resolves all pinned positions server-side before drawing. If you change a text layer's content and the text expands (e.g., from auto-size strategy), any elements pinned to it reposition automatically.

This is especially important for templates that have variable-length text — elements anchored below a text block will shift down to accommodate however much space the text actually needs.


Output Format and Quality#

Set format and quality per-request, or leave them unset to use the template's configured defaults.

FormatContent-TypeNotes
"png"image/pngLossless. Best for text-heavy images and transparency.
"jpeg"image/jpegLossy, smaller files. quality (1–100) controls compression.
"pdf"application/pdfRequires Pro plan. Use sizes array for multi-page output.

Multi-page PDF example:

{
  "template": "report-cover",
  "layers": { ... },
  "format": "pdf",
  "sizes": [
    { "width": 1000, "height": 1414 },
    { "width": 1000, "height": 1414 }
  ]
}

Each entry in sizes corresponds to one page. The same template and layers data is used for all pages; page-specific content is typically driven by the template's design using separate element groups per page.


Response Headers and Warnings#

Every render response includes these headers:

HeaderDescription
X-Render-IdUnique identifier for this render (useful for support/debugging)
X-Render-WarningsJSON array of non-fatal issues (unknown layers, type mismatches, etc.)
X-CacheHIT or MISS (GET renders only)

Warning object shape:

[
  {
    "element": "speaker_name",
    "code": "UNKNOWN_LAYER",
    "message": "Layer 'speaker_name' does not exist in template"
  },
  {
    "element": "schedule_items",
    "code": "REPEATER_NOT_ARRAY",
    "message": "Layer 'schedule_items' is a repeater but provided value is not an array"
  }
]

Common warning codes:

CodeMeaning
UNKNOWN_LAYERA layer key doesn't match any element's API Name in the template
REPEATER_NOT_ARRAYA repeater layer value must be an array
PRESIGNED_URL_IN_LAYERAn image src in layers is a short-lived pre-signed URL (GCS/AWS) that will expire — replace with a stable URL
MISSING_DYNAMIC_LAYERA dynamic element was omitted from layers; its template default value was rendered

Always log or monitor X-Render-Warnings during development. A typo in an API Name will silently produce output with default values rather than an error — the warning header is how you catch it.

Pre-signed URLs: If your automation pipeline fetches asset URLs by following a redirect (e.g., from a /objects/ path), you may receive a time-limited GCS or AWS pre-signed URL. Do not pass these directly as src values in your layers — they expire in minutes and will break your render history. Use a stable CDN or object-storage URL instead.


Plan Feature Gates#

Some element types require a specific plan. If your render request triggers a feature your organization's plan does not include, the API returns a 403 with a structured error:

{
  "error": "feature_not_available",
  "feature": "qr_codes",
  "message": "This template contains QR code layers which are not available on your current plan.",
  "upgrade_hint": "Available on Pro, Business, and Enterprise plans."
}
FeatureMinimum Plan
QR code elementsPro
Repeater elementsBusiness
PDF outputPro

Common Patterns#

Events application — generating attendee badges#

Fetch the template schema once at startup, then call the render API per attendee:

const response = await fetch("https://your-renderstack.com/api/v1/renders/sync", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.RENDERSTACK_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    template: "event-badge",
    layers: {
      attendee_name:  { text: attendee.fullName },
      job_title:      { text: attendee.title },
      company:        { text: attendee.company },
      session_track:  { text: attendee.track },
      track_color:    { fill: TRACK_COLORS[attendee.track] ?? "#6b7280" },
      headshot:       attendee.photoUrl ? { src: attendee.photoUrl, fillMode: "smart-cover" } : undefined,
      check_in_qr:    { value: `https://events.example.com/check-in?id=${attendee.id}` },
    },
    format: "png",
    quality: 95,
  }),
});

const imageBuffer = await response.arrayBuffer();

Omitting headshot entirely (or setting it to undefined) causes the headshot layer to be absent from layers. If the template uses auto-visibility, the frame simply won't render — no placeholder, no broken image.


Variable-length schedule — using a repeater#

body: JSON.stringify({
  template: "event-schedule",
  layers: {
    event_title: { text: event.name },
    event_date:  { text: formatDate(event.date) },
    sessions: event.sessions.map(session => ({
      session_title:  { text: session.name },
      session_time:   { text: `${session.startTime} – ${session.endTime}` },
      speaker_name:   { text: session.speaker },
      session_image:  session.thumbnailUrl ? { src: session.thumbnailUrl } : undefined,
    })),
  },
})

The repeater handles all layout — spacing, overflow clipping, and grid arrangement are resolved automatically from the template configuration. If you supply 12 sessions and the template designer set maxItems: 10, you'll get exactly 10 rows with no error.


Embedding a dynamic OG image in your web app#

Use a GET key to generate a dynamic Open Graph image:

<meta property="og:image" content="https://your-renderstack.com/api/v1/render
  ?apiKey=rs_get_YOUR_KEY
  &template=event-og-card
  &event_title.text=Tech+Summit+2026
  &event_date.text=June+12%2C+2026
  &location.text=San+Francisco%2C+CA
  &hero_image.src=https%3A%2F%2Fcdn.example.com%2Fevents%2Fsummit.jpg" />

The URL is constructed per page. The render is cached, so repeated requests for the same parameter set are served instantly.