Render print-ready PDFs from your templates with a single HTTP call. The whole API is plain JSON over HTTPS, so it drops straight into n8n, Make.com, Zapier, Pipedream, or any other automation platform — no SDK, no webhooks to configure, just one HTTP Request node per step.
Introduction
Print Studio exposes a JSON HTTP API for rendering designs from saved templates. You provide a template_id and a set of field values (text, colors, image URLs) — the service substitutes them into the template, renders a print-ready PDF with optional CMYK conversion, and returns a signed CDN URL.
The API is plain HTTP + JSON, which means you can drive it from n8n, Make.com, Zapier, Pipedream, Activepieces, Retool Workflows, or any cURL-friendly tool — no SDK to install. Every endpoint card below ships with a dedicated n8n / Make tab that you can copy straight into an HTTP Request node.
Two rendering modes are available: synchronous (POST /api/process) which blocks until the PDF is ready and returns the URL directly, and asynchronous (POST /api/jobs) which returns a jobId immediately and lets you poll for completion. Use sync for low-volume / user-facing flows and most n8n workflows; use async for bulk batches, scheduled runs, or long-running renders that exceed the platform's HTTP timeout.
Use with n8n / Make / Zapier
Every endpoint below ships with a paste-ready cURL on its n8n / Make tab. The flow is the same on every platform: copy the cURL, paste it into your HTTP step, replace YOUR_API_SECRET_KEY with your real key (or a credential reference), and hit run.
n8n — 30 seconds, no manual config
Add an HTTP Request node.
Click the ⋯ menu in the node header → Import cURL command.
Paste the cURL from the endpoint's n8n / Make tab. n8n auto-fills Method, URL, Headers, and Body in one shot.
For the API key, switch Authentication to Header Auth with name Authorization and value Bearer {{ $env.API_SECRET_KEY }} — that way the secret stays out of the workflow JSON.
Wire dynamic data into the body with {{ $json.x }} expressions — exec.
Make.com
Add an HTTP > Make a request module.
Read the cURL tab and copy URL + Method straight in. Add an Authorization header of Bearer YOUR_KEY (store the key in a connection rather than the scenario).
Pick Body type: Raw, Content type: JSON, paste the JSON from the cURL -d argument, swap {{ $json.x }} placeholders for Make's {{1.x}} tokens.
Copy the URL, Method, and Authorization header from the cURL. Paste the JSON body from -d '...' into the body field.
Rewrite {{ $json.x }} placeholders in the host's template syntax (e.g. {{step1.x}} on Zapier).
Workflow patterns
Sync render (≤ 30s): one POST /api/process node; map outputUrl downstream.
Async render: POST /api/jobs → Wait → GET /api/jobs/{jobId} in a loop until job.status === "completed".
Bulk render: Split In Batches (n8n) / Iterator (Make) over a CSV → one POST /api/jobs per row.
Template picker: GET /api/templates → expose id + name as a dropdown in your form.
Security: the API_SECRET_KEY is a server-side credential. Always store it as an n8n Header Auth credential / Make connection / Zapier hidden field and reference it from the workflow — never paste the raw key into a shared scenario or a browser-side automation.
Authentication
All integration endpoints require a server-side API key, passed as a Bearer token:
Authorization: Bearer ps_live_<your-key>
Keys are managed from the operations dashboard at /dashboard. From there you can generate keys, set per-endpoint scopes (render, external-jobs, templates:read, jobs:read), revoke keys, and see lifetime usage per key. The plaintext value is shown only once at creation — store it in your partner's secret manager.
A request that authenticates but lacks the scope a route requires returns 403 Insufficient scope. A request with no or an invalid token returns 401 Unauthorized.
Legacy env-var values (API_SECRET_KEY, MAGENTO_API_KEY) are auto-seeded into the dashboard's key database on first run, so any partner already integrated against those tokens keeps working — the values now show up as "Legacy" entries in the dashboard and can be revoked once partners have rotated to a freshly generated key.
Conventions
All requests and responses use JSON with UTF-8 encoding.
Field tags must be lowercase snake_case: ^[a-z0-9_]+$.
Colors can be expressed as { rgb: "#RRGGBB" } or with an explicit CMYK override { rgb: "#RRGGBB", cmyk: { c, m, y, k } }. The renderer picks the right space based on the template's colorProfile.
Asset URLs (logo, pic) must be publicly reachable HTTPS endpoints returning image/png, image/jpeg, or image/webp under 10 MB.
Timestamps are ISO 8601 UTC strings.
Errors
Errors return a non-2xx status code and a JSON body of the shape{ error: string, details?: object[] }. Validation errors include adetailsarray with per-field messages.
{
"error": "Validation failed",
"details": [
{ "field": "fields.0.tag", "message": "tag must be lowercase letters, numbers, and underscores only" }
]
}
POST/api/processAPI key
Render a PDF synchronously
Substitutes your field values into the template, renders the artwork with Puppeteer, converts to CMYK when the template's colorProfile is 'cmyk', and uploads the output to CDN storage. The response includes URLs for the final PDF, an editable .pst for the Studio, and a thumbnail PNG.
Body Parameters
Name
Type
Required
Description
template_id
string
required
ID of a saved template (from GET /api/templates).
fields
Field[]
required
Values keyed by tag. Each field carries a text/URL value and optional color overrides (color / fillColor / strokeColor).
assets
{ logo?, pic? }
optional
Public HTTPS URLs for image slots. Must be PNG/JPEG/WEBP under 10 MB.
palette
{ primary?, secondary?, tertiary? }
optional
Source of truth for role-colored shapes and fallback for text fields that declare a role.
notification
{ name?, notify_email?, notify_slack? }
optional
Customer name (baked into output PDF / PST filenames) and optional email or Slack handle for downstream delivery notifications.
`outputUrl` is always present on success. `editableUrl` and `thumbnailUrl` may be null if PST generation fails (the print-ready PDF still uploads — PST is non-fatal).
Same request shape as /api/process, but the job is pushed onto the render queue and the endpoint returns immediately. Use this for bulk runs, long-running renders, or any flow where you'd rather poll than block.
Returns the current state of a queued job. Poll this endpoint every 1–3 seconds after queueing. When status is 'completed', outputUrl / editableUrl / thumbnailUrl are populated.
Path Parameters
Name
Type
Required
Description
jobId
string
required
The id returned from POST /api/jobs.
Response (200 OK)
status ∈ { waiting, active, completed, failed, delayed }.
Returns every saved template with its id, human-readable name, thumbnail URL, updatedAt, and the tags of required fields. First-load responses return fast and warm the in-process cache in the background — subsequent calls include full metadata. The `hits` and `cached` fields are for observability and can be ignored by integrators.
Response (200 OK)
On a cold start, name may equal the template id and requiredFields may be empty until the background warm completes (~1–2s after the first call).
Returns the full Template object (canvas config, manifest fields, color profile) and the raw Fabric.js canvasJson. The manifest is the source of truth for which tags are required when calling /api/process — use it to dynamically build the form you render to end users.
A separate intake endpoint for the client's Magento storefront. The web team posts a fixed payload (ContactInfo1–8, Logo / AltLogo, Photo / AltPhoto, ComplimentsOf, CustomerId) and the design is queued under the CustomerId they supplied — so the identifier is the same on both sides.
Field mapping
Magento field
Print-studio tag
Notes
ContactInfo1
company_name
text
ContactInfo2
phone
text
ContactInfo3
website
text
ContactInfo4
slogan
text
ContactInfo5
email
text
ContactInfo6
custom_1
text · “Other”
ContactInfo7
custom_2
text · “Other”
ContactInfo8
custom_3
text · “Other”
ComplimentsOf
compliments_of
text
Logo
assets.logo
image · HTTPS URL
AltLogo
assets.alt_logo
image · fallback or hidden layer
Photo
assets.pic
image · HTTPS URL
AltPhoto
assets.alt_pic
image · fallback or hidden layer
Alt images & overflow values
If Logo/Photo HEAD-validates successfully, the corresponding AltLogo/AltPhoto rides along as a visible: false hidden layer on the saved PST. The rendered PDF does NOT include hidden content.
If the primary URL fails (404, wrong content-type, >10 MB), the alt is promoted into the primary slot. The job is flagged Manual Review and the reason is recorded on the job record.
Text fields whose tag is not present in the chosen template (e.g. custom_1/2/3 when the template only has company_name and phone) become hidden text layers in the same way. Manual Review is flagged.
All such jobs appear in the Operations dashboard with an amber Review badge so the print team can open the PST and decide what to keep, move, or delete before sending to press.
CustomerId rules
The value of CustomerId is used verbatim as the BullMQ job id, the S3 storage prefix, and the identifier returned to the partner.
Posting the same CustomerId twice returns 409 Conflict — the partner must mint a new id to retry. We never silently overwrite a prior design.
Retries
A 5xx response means our backend was temporarily unavailable — retry the same request with exponential backoff (e.g. 1s, 5s, 30s). Retries are safe because of CustomerId deduplication: a CustomerId that was already queued by an earlier attempt returns 409 instead of creating a second job, so you will never accidentally render the same design twice.
POST/api/external/jobsAPI key
Queue an async job (Magento / external partners)
Async, fire-and-forget intake for the client's Magento storefront. Accepts the partner's fixed payload shape, maps it onto internal tags, performs HEAD-validation on supplied image URLs (with Alt fallback), and enqueues the job under the partner-supplied CustomerId. The partner does not need to poll — a future Zoho push surfaces the finished design on their side.
Body Parameters
Name
Type
Required
Description
CustomerId
string
required
Used verbatim as the print-studio job id. [a-zA-Z0-9_-]+, max 128 chars. Duplicates return 409.
template_id
string
required
Print Studio template id (from GET /api/templates).
ContactInfo1..8
string
optional
Text fields. 1–5 map to canonical tags (company_name, phone, website, slogan, email); 6–8 to custom_1/2/3. Empty strings are dropped; unmapped values become hidden text layers + Manual Review.
Logo / AltLogo
string (URL)
optional
HTTPS URLs to PNG/JPEG/WEBP under 10 MB. If primary fails HEAD-validation, alt is promoted into the primary slot and the job is flagged Manual Review. If primary succeeds, alt rides along as a hidden layer.
HTTP 202 — the response is always { success, jobId } where jobId === CustomerId. There is no callback; status, if needed, can be polled at GET /api/jobs/{CustomerId}.