Inkspan › Guides › How to generate a PDF from a template in cURL

How to generate a PDF from a template in cURL

Most documents are one layout rendered against changing data: the same invoice for a thousand customers, the same certificate for every course completion. The /v1/generate/template endpoint separates those concerns — you POST a Jinja2 template plus a JSON data object, and Inkspan renders the template and converts the result to PDF in one request.

Keeping the template in the request rather than in your codebase means non-engineers can change document layout without a deploy, and you can store templates in your own database per tenant.

Also in: Python · Node.js

cURL example

curl -X POST https://api.inkspan.dev/v1/generate/template \
  -H "X-API-Key: ink_live_..." \
  -H "Content-Type: application/json" \
  -d '{"template": "<h1>Invoice {{ number }}</h1>{% for i in items %}<p>{{ i.desc }}: ${{ i.amt }}</p>{% endfor %}<h3>Total: ${{ total }}</h3>", "data": {"number": "INV-1042", "items": [{"desc": "Pro Plan", "amt": 49}], "total": 49}}' \
  --output document.pdf

Request parameters

NameTypeRequiredDescription
templatestringyesA Jinja2 template. Supports {{ variables }}, {% for %} loops, {% if %} conditionals, and filters.
dataobjectyesJSON object whose top-level keys become template variables.
filenamestringnoFilename in the response's Content-Disposition.

Response

Returns a PDF as a binary stream with Content-Type: application/pdf and Content-Disposition: attachment; filename=document.pdf. Write the response body straight to disk — do not parse it as JSON.

Things that catch people out

Errors

StatusMeaningFix
401Invalid or missing API keySend your key in the X-API-Key header.
402Monthly quota exceededThe response reports used/quota. Upgrade at inkspan.dev/#pricing.
422Missing or invalid parameterCheck required fields in the table above — the body names the offending field.

Failed requests do not count against your quota; only successful ones are metered.

Frequently asked questions

Can I reuse a stored template?

Templates are sent per request, so store yours in your own database or object storage and send it with each call. This keeps tenant-specific layouts under your control.

Do Jinja2 filters work?

Yes — standard filters such as |round, |upper, and |default are available for formatting values inside the template.

How do I format currency?

Format on your side before sending, or use a filter in the template. Sending pre-formatted strings is the more predictable option for money.

Get a free API key →

Related Generate guides: generate a PDF from HTML · convert Markdown to PDF