Receipt Generation API

Receipt generation API: a PDF receipt for every payment

When a payment succeeds in your system, your customer gets a branded receipt — automatically, in A4, Letter or thermal width, attached to the email you were already sending.

  • 50 free renders/month
  • No credit card
  • 58 mm, 80 mm, A4 or Letter

What is a receipt generation API?

A receipt generation API turns a completed payment into a document the customer can keep. Your system sends the amount, the payment method, the line items and the date; the API fills them into your branded template and returns a PDF or image — usually within a second of the payment settling, ready to attach to the confirmation email.

Three different things are called a “receipt API”. Some services read receipts, turning a photo into structured data with OCR. Some payment providers deliver a receipt as part of their own checkout, in their layout. This one creates the document from data you already hold, in your design — for the payments your business takes.

Receipt generation API key facts
EndpointPOST https://api.dynamicdocumentapi.com/v1/pdf/from-template, or /v1/images/from-template for a PNG receipt
InputYour payment data as JSON: amount, currency, method, line items, tax, timestamp
PaperA4, Letter, or a custom width such as 80 mm and 58 mm for roll printers; height follows the content with single_page
FormattingAny currency and locale, formatted with Unicode CLDR data; your time zone via timezone
CodesQR codes for a re-download link or a review page, plus 16 barcode types
DuplicatesAn Idempotency-Key per payment ID: a webhook delivered twice still produces one receipt (24 hours)
DeliverySigned URL (1 hour default, up to 7 days), binary for email attachments, or base64
Render timeMedian 216 ms, p95 516 ms1
PriceFree: 50 renders/month. Paid from €15/month (billed annually) for 3,000 renders, auto top-ups from €6 per 1,000, about €0.005 per receipt

1. Measured over 1,664 successful renders on engine 2026.4. total_ms = time in the queue plus processing in the worker, excluding API overhead and network transfer. Receipts are small documents and sit at the fast end of that range.

Receipt or invoice — which one do you need?

The two documents are often built from the same data, and just as often confused. The difference is the direction of the money.

  • An invoice asks for payment. It carries an invoice number, a due date, payment terms and, in most countries, a set of legally required fields. If that is what you need, the invoice PDF API covers it, including multi-page line items and tax columns.
  • A receipt confirms payment. It names the amount actually paid, the method, the last four digits of the card, the time and the transaction reference. It is shorter, it is issued after the fact, and it never has a due date.

Many businesses send both: an invoice with the order, a receipt when the payment settles. One template library can hold both, and they can share the same header, logo and footer.

Generate a receipt from a payment event

The trigger is a webhook from your payment provider — Stripe, Adyen, Mollie, PayPal or your own point of sale. Your handler maps the event to receipt data and calls the API with the payment ID as the idempotency key.

curl https://api.dynamicdocumentapi.com/v1/pdf/from-template \
  -H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY" \
  -H "Idempotency-Key: pi_3Qk8sLd92" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_receipt_thermal",
    "data": {
      "receipt_no": "R-2026-18422",
      "paid_at": "2026-09-25T10:14:02Z",
      "method": "Visa •••• 4242",
      "locale": "en-US",
      "currency": "USD",
      "items": [
        { "name": "Flat white", "qty": 2, "total": 7.80 },
        { "name": "Croissant",  "qty": 1, "total": 3.68 }
      ],
      "subtotal": 11.48, "tax": 1.42, "total": 12.90,
      "reprint_url": "https://shop.example.com/r/R-2026-18422"
    },
    "pdf": {
      "paper": { "width": "80mm" },
      "single_page": true,
      "margin": { "top": "4mm", "right": "3mm", "bottom": "4mm", "left": "3mm" },
      "timezone": "America/New_York"
    },
    "delivery": "binary"
  }' \
  --output receipt.pdf
// Node.js 18+: called from your payment webhook handler
export async function receiptFor(payment) {
  const res = await fetch("https://api.dynamicdocumentapi.com/v1/pdf/from-template", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.DYNAMIC_DOCUMENT_API_KEY}`,
      "Idempotency-Key": payment.id, // providers retry webhooks
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      template_id: "tpl_receipt",
      data: {
        receipt_no: payment.receiptNo,
        paid_at: payment.paidAt,
        method: `${payment.brand} •••• ${payment.last4}`,
        currency: payment.currency,
        items: payment.items,
        total: payment.total,
      },
      pdf: { paper: { format: "A4" } },
      delivery: "binary", // bytes for the email attachment
    }),
  });
  if (!res.ok) throw new Error(await res.text());
  return Buffer.from(await res.arrayBuffer());
}
import os
import requests

def receipt_pdf(payment: dict, thermal: bool = False) -> bytes:
    """Called from the payment webhook. Returns PDF bytes."""
    paper = {"width": "80mm"} if thermal else {"format": "A4"}
    res = requests.post(
        "https://api.dynamicdocumentapi.com/v1/pdf/from-template",
        headers={
            "Authorization": f"Bearer {os.environ['DYNAMIC_DOCUMENT_API_KEY']}",
            "Idempotency-Key": payment["id"],
        },
        json={
            "template_id": "tpl_receipt",
            "data": payment,
            "pdf": {"paper": paper, "single_page": thermal},
            "delivery": "binary",
        },
        timeout=30,
    )
    res.raise_for_status()
    return res.content
<?php
function receiptPdf(array $payment): string
{
    $ch = curl_init('https://api.dynamicdocumentapi.com/v1/pdf/from-template');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . getenv('DYNAMIC_DOCUMENT_API_KEY'),
            'Idempotency-Key: ' . $payment['id'],
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS     => json_encode([
            'template_id' => 'tpl_receipt',
            'data'        => $payment,
            'pdf'         => [
                'paper'       => ['width' => '58mm'], // narrow roll printer
                'single_page' => true,
            ],
            'delivery'    => 'binary',
        ]),
    ]);
    return curl_exec($ch); // PDF bytes
}

Payment providers retry webhooks, so the same event often arrives twice. With the payment ID as Idempotency-Key, the second call returns the receipt that was already rendered instead of creating another one — for 24 hours. Test keys let you replay real events against watermarked output without spending quota.

Thermal roll, A4 or an image — the same receipt

Where the receipt ends up decides its shape. A roll printer at the counter wants a narrow, endless strip; an accounting inbox wants A4 or Letter; a confirmation email often looks better with the receipt shown as a picture. All three come from one template.

80 mm and 58 mm rolls

Set the paper width directly and let the height follow the content. With single_page the PDF is one continuous page, so a two-item sale prints short and a twenty-item sale prints long — no blank tail, no cut-off totals.

"paper": { "width": "80mm" },
"single_page": true,
"margin": { "left": "3mm", "right": "3mm" }

A4 and Letter for the archive

The same data through a wider template gives the document an accountant expects: your address block, the tax summary, the transaction reference. Thirteen named page sizes are available, or any custom size up to 200 inches.

PNG for the email body

Some customers never open attachments. The image generation API renders the same template as a PNG or JPG you can show inline, at the viewport and scale you choose.

Currency, locale and time zone

Amounts, decimal separators and dates follow Unicode CLDR rules for the locale you pass, and timezone makes sure “10:14” means the customer's local time rather than your server's.

Refunds, partial payments and donations

One template can serve every variation your checkout produces, because the layout reacts to the data. A condition decides whether a block appears at all.

{% if refund %}
  <h1>Refund receipt</h1>
  <p class="ref">Refunds {{ original_no }}</p>
{% elif balance > 0 %}
  <h1>Partial payment</h1>
  <p class="bal">Remaining: {{ balance | format_currency(currency, locale) }}</p>
{% else %}
  <h1>Receipt</h1>
{% endif %}

The same mechanism adds a tip line for a point-of-sale payment, a donor block and charity registration number for a donation receipt, or a note that a payment was made in instalments. What each document has to say is your accountant's call; the template renders it, and every version of that template is kept so you can see exactly what a customer received last March.

Getting the receipt to the customer

  • Email attachment. "delivery": "binary" returns the bytes, ready for your email provider's attachment field. The API creates the document; sending stays with the system that already sends your confirmations.
  • Download link. The default response carries a signed URL, valid for an hour and up to seven days with expires_in — long enough for a “view your receipt” button in the confirmation email.
  • Customer portal. Store the render ID with the payment and generate a fresh link whenever the customer opens their order history.
  • Counter printing. The thermal PDF goes straight to a roll printer from your point-of-sale software.
  • Retention you control. Files live for as long as you set with retention_days, up to your plan's maximum, and can be deleted at any time. Tax law decides how long you must keep the record — keep your own archive copy, for example in your own storage bucket.

What a receipt costs to generate

Free

€0

50 receipts per month — enough to wire up the webhook and test both paper widths.

Starter

€15 / month

3,000 renders per month, billed annually (€19 billed monthly). About €0.005 per receipt.

High-volume checkouts scale on the Growth plan: 15,000 renders for €47 billed annually, about €0.0031 per receipt, with automatic top-ups when a month runs hot. See the cost per receipt on every plan.

FAQ

Receipt generation API: frequently asked questions

What is the difference between a receipt and an invoice?

An invoice asks for money: it lists what is owed, a due date and payment terms. A receipt confirms that money has arrived: it names the amount paid, the method and the date. Many businesses send both — an invoice at order time, a receipt when the payment settles.

Can I generate receipts in thermal-printer width?

Yes. Set a custom paper width of 80 mm or 58 mm and switch on single_page, so the page height follows the content instead of being cut into A4 pages. A short receipt stays short and a long one simply gets longer, exactly like a roll printer expects.

Can receipts be sent automatically after a Stripe payment?

Yes, from your own webhook handler. When your payment provider reports a successful charge, your code maps the event to receipt data and calls the API with the payment ID as idempotency key. Providers retry webhooks, and that key makes sure a duplicate event does not create a second receipt.

Can I create donation receipts?

Yes. A donation receipt is the same template with different fields: donor, amount, date, your charity registration number and any wording your tax authority requires. What that wording must be is a question for your accountant; the API renders whatever your template says.

Can one template handle refunds and partial payments?

Yes. Templates use conditions, so the same file can print a refund receipt with a negative total, show “partially paid” with a remaining balance, or add a tip line for a point-of-sale payment, depending on the data you send.

Does this read data from photos of receipts?

No. That is receipt OCR, which goes the other way: a picture in, structured data out. This API creates receipts from data you already have. If you need to extract data from scanned receipts, an OCR service is the right tool.

Send your first receipt free

50 renders a month on the free plan, no credit card, auto top-ups on paid plans.

Start free