Quire PDFGuides

Turn any JSON into a PDF with one API call

POST your JSON object to https://api.quirepdf.dev/v1/render with your API key, and the response body is the PDF. No template is needed; to make it read like a real document, add a title, from and to, set currency, and order the keys the way you want the sections to appear.

curl https://api.quirepdf.dev/v1/render \
  -H "Authorization: Bearer $QUIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @data.json \
  -o data.pdf

That’s the whole integration. Get a key with npx quirepdf-cli login [email protected]; the free plan includes 20 renders a month, and watermarked test renders (?test=true) are unlimited while you build.

Quire takes any JSON object up to 1 MB. If the data looks like an invoice, receipt, quote, credit note, statement or certificate, it uses that template. Otherwise it uses a generic layout that turns keys into sections, objects into key/value grids and arrays of objects into tables.

Raw JSON works, but reads like a dump

Here’s an export straight from a reporting database:

{
  "id": "rep_7Hq2",
  "account": { "id": "acct_19", "name": "Little Owl Café" },
  "period_start": "2026-09-01T00:00:00Z",
  "period_end": "2026-09-30T23:59:59Z",
  "stats": { "orders": 1284, "revenue_cents": 2391450, "avg": 18.62 },
  "top": [
    { "name": "Flat white", "n": 412, "rev": 185400 },
    { "name": "Croissant", "n": 388, "rev": 112520 }
  ]
}

It renders, and the PDF is tidy: a “Document” heading, a Details panel with the ID and the two timestamps, an Account section, a Stats grid and a two-column table. But the heading is generic, the timestamps are ISO strings, revenue is in cents, and columns are called “N” and “Rev”. Quire prints what you send. A few minutes of shaping fixes all of it.

Shaped JSON reads like a report

{
  "title": "Monthly sales report",
  "subtitle": "September 2026",
  "number": "REP-2026-09",
  "date": "1 Oct 2026",
  "currency": "$",
  "from": { "name": "Ledgerly", "email": "[email protected]" },
  "to": { "name": "Little Owl Café", "address": ["88 Alder Lane", "Portland, OR 97205"] },
  "orders": 1284,
  "average_order_amount": 18.62,
  "summary": "Revenue rose 6% on August, driven by the new breakfast menu. Weekday mornings are now 41% of orders; Sunday afternoons remain the slowest period.",
  "top_products": [
    { "product": "Flat white", "units": 412, "sales_amount": 1854.0 },
    { "product": "Croissant", "units": 388, "sales_amount": 1125.2 },
    { "product": "Breakfast burrito", "units": 236, "sales_amount": 2124.0 }
  ],
  "totals": { "gross_total": 23914.5, "refunds": 182.0, "net_total": 23732.5 },
  "notes": "Figures exclude gift card sales. Contact [email protected] with questions."
}

The result:

  • A letterhead with the Ledgerly mark and email on the left, and “Monthly sales report” with REP-2026-09 on the right, then “September 2026” underneath.
  • A To block for Little Owl Café beside a Details panel: Date, Orders 1,284, Average order amount $18.62.
  • A Summary paragraph, because the string is longer than 80 characters.
  • A Top products table with right-aligned Units and Sales amount columns ($1,854.00).
  • A Totals grid: $23,914.50, $182.00, $23,732.50.
  • A Notes block, and a footer reading “Monthly sales report · REP-2026-09” with “1 of 1”.

What made the difference

Change Why
Added title, subtitle, number, date These reserved keys build the header and footer
Added from and to from becomes the letterhead; to becomes an addressed block
Set currency Numbers whose keys contain amount, total, price, cost, fee, tax, refund and similar words print as money
Renamed rev to sales_amount and sent dollars, not cents Only money-like key names get money formatting, and Quire doesn’t convert units
Pre-formatted dates Quire prints strings exactly as given
Dropped internal IDs Every key you send becomes part of the page
Ordered keys deliberately Sections appear in your JSON’s key order
Sent the totals The generic layout never sums a column for you

The full list of rules, including how nested objects and mixed arrays render, is in Templates and layout.

Check before you render

Validation is free and tells you which layout your data will get:

curl https://api.quirepdf.dev/v1/validate \
  -H "Authorization: Bearer $QUIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @report.json
{ "valid": true, "template": "document", "source": "fallback", "hint": null, "errors": [] }

If hint names a template, such as invoice (seller is required), your data is one or two fields away from a purpose-built layout that also computes totals. Add the missing field, or name the template with ?template=invoice to see every problem.

Preview without opening the PDF

curl "https://api.quirepdf.dev/v1/render?format=png" \
  -H "Authorization: Bearer $QUIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @report.json -o report.png

format=png returns the first page as an image (add &page=2 for another). It’s handy for thumbnails, emails and visual tests. The x-pages response header tells you how many pages the document has.

From a pipeline or cron job

The CLI wraps the same call and reads stdin, so it fits in a shell pipeline:

export QUIRE_API_KEY=qk_live_...
./export-report.sh | npx quirepdf-cli render - -o "report-$(date +%Y-%m).pdf"

It exits with code 1 and prints every problem if the data is rejected, so a failed render fails the job.

Limits

Requests can be up to 1 MB, render for up to 5 seconds and produce up to 200 pages. Only successful renders count against your monthly quota. See the Render API reference for every parameter and header.