Skip to content

Invoices from Shopify orders

Each time an order is paid in your Shopify store, Typefold can render its invoice from a template of your own, ready to email to the customer or store. The template reads the order as Shopify sends it, so there is no data to convert.

  • A Shopify store where you can add apps, or a development store to try this on.
  • An API key with render:create, render:read and template:read.

Make a template called Shopify invoice and use a Shopify order as its sample data. This order has the fields an invoice usually needs:

order.json
{
"id": 6012345678901,
"name": "#1001",
"order_number": 1001,
"created_at": "2026-10-25T14:03:11+02:00",
"email": "[email protected]",
"currency": "EUR",
"billing_address": {
"name": "Marta Tamm",
"address1": "Tartu mnt 2",
"zip": "10115",
"city": "Tallinn",
"country": "Estonia"
},
"line_items": [
{ "title": "Linen shirt", "quantity": 2, "price": "49.00" },
{ "title": "Canvas tote", "quantity": 1, "price": "19.00" }
],
"subtotal_price": "117.00",
"total_tax": "22.23",
"total_price": "139.23"
}
  • In the visual editor, paste it under Lay out from JSON data in the Data tab, and every field gets a block to style; see sample data.

  • In the code editor, save it as the template’s sample data, as in Build a template, and print its fields:

    <h1>Invoice {{name}}</h1>
    <p>{{format created_at type="date" dateStyle="long"}}</p>
    <p>{{billing_address.name}}<br />{{billing_address.address1}}<br />
    {{billing_address.zip}} {{billing_address.city}}<br />{{billing_address.country}}</p>
    <table>
    {{#each line_items}}
    <tr><td>{{title}}</td><td>{{quantity}}</td><td>{{price}} {{../currency}}</td></tr>
    {{/each}}
    </table>
    <p>Tax {{total_tax}} {{currency}}<br />Total {{total_price}} {{currency}}</p>

Shopify sends amounts as text, such as "49.00", so print them as they are; the format helper formats numbers only. Shopify’s webhooks reference lists every other field of the orders/paid topic, such as shipping_address, discount_codes and each item’s sku.

Publish the template when it looks right.

Pick the tool you already use.

  1. Install the Typefold nodes and connect them, as in n8n.
  2. Download the Shopify invoice workflow and import it in n8n: open a new workflow, click ⋯ at the top right and choose Import from File.
  3. Open Shopify Trigger and connect your store; see n8n’s Shopify credentials. It listens for Order Paid.
  4. Open Typefold and pick your Typefold credential. It renders Shopify invoice with the whole order as Data.
  5. Open Send Email, connect your mail server and change From Email. It sends the PDF to the order’s email address. To store the PDF instead, replace it with a Google Drive, Dropbox or S3 node.
  6. Activate the workflow.
  1. Connect Typefold, as in Zapier.
  2. Start a Zap with Shopify and the New Paid Order trigger, and test it to load an order.
  3. Add Typefold → Render Report and pick Shopify invoice. Its fields are named after the sample order, such as billing_address › name; map the order’s values into them. For the items, map line_items › title, line_items › quantity and line_items › price to the order’s line item values.
  4. Add an email step, such as Gmail → Send Email, with the Typefold step’s File as the attachment.
  1. In your Shopify app, subscribe to the orders/paid topic with your endpoint’s URL; see Shopify’s webhooks guide.
  2. In the endpoint, check the X-Shopify-Hmac-SHA256 header against the body with your app’s client secret, then answer 200 within 5 seconds, Shopify’s time limit. Render the invoice after answering, for example from a queue.
  3. Render the template with the order as its data. The order’s id makes a good idempotency key, so when Shopify sends an order twice, you get the first invoice back instead of a second one.

curl can’t check Shopify’s signature, but it can render a saved order to try the template:

Terminal window
curl "$PDF_URL/v1/reports/render" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/json" \
--fail-with-body -o invoice.pdf \
-d "{\"template\": {\"name\": \"Shopify invoice\"}, \"data\": $(cat order.json)}"

Read the body as raw bytes, before any JSON parsing, or the signature won’t match.

Each invoice is one document of your plan; see pricing. To try the flow without using documents, turn on Test Render in n8n or Test render in Zapier, or add "test": true to the request, and every page gets a “TEST” watermark.