PaperPony

Recipe

Shipping label template

An A6 shipping label template for the PaperPony PDF API, sized for a thermal label printer with large addresses and a service band.

Worth knowing

  • The page is A6, 105 by 148 mm, with zero margin, because a label printer has no margins and anything you leave is cropped. A6 is the closest named format to the 4 by 6 inch label stock.
  • Set the size through options.format. There is no width or height option, and the request is rejected if you send one. Printing a label on A4 and expecting the printer to scale is how labels come out unreadable.
  • Barcodes are images. Generate the PNG yourself and pass it as a data URL, or reference it over HTTPS. There is no barcode helper, and there should not be one.

The template

Store it once with POST /v1/templates. It is compiled when you store it, so a mistake surfaces now rather than on the first render.

shipping-label.hbs
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    *, *::before, *::after { box-sizing: border-box; }
    body {
      margin: 0;
      font-family: 'Noto Sans', sans-serif;
      font-size: 10pt;
      line-height: 1.5;
      color: #111827;
      -webkit-print-color-adjust: exact;
      print-color-adjust: exact;
    }
    table { border-collapse: collapse; width: 100%; }
    thead { display: table-header-group; }
    tr { break-inside: avoid; }
    .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
    body {
      width: 105mm;
      height: 148mm;
      padding: 4mm;
      display: flex;
      flex-direction: column;
      font-size: 9pt;
    }
    .service {
      background: #111827;
      color: #fff;
      padding: 2mm 3mm;
      font-size: 13pt;
      font-weight: 700;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      display: flex;
      justify-content: space-between;
    }
    .block { border-bottom: 1px solid #111827; padding: 3mm 0; }
    .label {
      font-size: 7pt;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: #6b7280;
    }
    .to { font-size: 13pt; font-weight: 700; line-height: 1.3; white-space: pre-line; }
    .from { color: #374151; white-space: pre-line; }
    .tracking {
      margin-top: auto;
      text-align: center;
      font-family: 'Noto Sans Mono', monospace;
    }
    .tracking img { display: block; width: 100%; height: 0.9in; object-fit: contain; }
    .tracking .code { margin-top: 1.5mm; font-size: 11pt; letter-spacing: 0.08em; }
  </style>
</head>
<body>
  <div class="service">
    <span>{{service}}</span>
    <span>{{weight}}</span>
  </div>

  <div class="block">
    <div class="label">From</div>
    <div class="from">{{sender.name}}
{{sender.address}}</div>
  </div>

  <div class="block">
    <div class="label">Ship to</div>
    <div class="to">{{recipient.name}}
{{recipient.address}}</div>
  </div>

  {{#if reference}}
    <div class="block">
      <div class="label">Reference</div>
      <div>{{reference}}</div>
    </div>
  {{/if}}

  <div class="tracking">
    {{#if barcode_url}}<img src="{{barcode_url}}" alt="">{{/if}}
    <div class="code">{{tracking_number}}</div>
  </div>
</body>
</html>

Rendering it

Substitute the template id you got back, and send this payload.

curl https://api.paperpony.dev/v1/pdf/render \
  -H "Authorization: Bearer $PAPERPONY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "template_id": "tpl_YOUR_TEMPLATE_ID",
  "data": {
    "service": "Express",
    "weight": "2.4 kg",
    "sender": {
      "name": "Northwind Studio",
      "address": "14 Bridgewater Street\nManchester M15 4RN\nUnited Kingdom"
    },
    "recipient": {
      "name": "Fabrikam Ltd",
      "address": "9 Peveril Road\nSheffield S11 7AQ\nUnited Kingdom"
    },
    "reference": "PO-99213",
    "tracking_number": "NW 4821 7734 GB",
    "barcode_url": "https://cdn.example.com/barcodes/NW48217734GB.png"
  },
  "options": {
    "format": "A6",
    "margin": {
      "top": "0",
      "right": "0",
      "bottom": "0",
      "left": "0"
    },
    "print_background": true,
    "wait_for": "networkidle"
  }
}'
import { PaperPony } from 'paperpony';

const pony = new PaperPony({ apiKey: process.env.PAPERPONY_API_KEY });

const job = await pony.pdf.render({
  "template_id": "tpl_YOUR_TEMPLATE_ID",
  "data": {
    "service": "Express",
    "weight": "2.4 kg",
    "sender": {
      "name": "Northwind Studio",
      "address": "14 Bridgewater Street\nManchester M15 4RN\nUnited Kingdom"
    },
    "recipient": {
      "name": "Fabrikam Ltd",
      "address": "9 Peveril Road\nSheffield S11 7AQ\nUnited Kingdom"
    },
    "reference": "PO-99213",
    "tracking_number": "NW 4821 7734 GB",
    "barcode_url": "https://cdn.example.com/barcodes/NW48217734GB.png"
  },
  "options": {
    "format": "A6",
    "margin": {
      "top": "0",
      "right": "0",
      "bottom": "0",
      "left": "0"
    },
    "print_background": true,
    "wait_for": "networkidle"
  }
});

console.log(job.output_url);
import os
import requests

response = requests.post(
    "https://api.paperpony.dev/v1/pdf/render",
    headers={"Authorization": f"Bearer {os.environ['PAPERPONY_API_KEY']}"},
    json={
    "template_id": "tpl_YOUR_TEMPLATE_ID",
    "data": {
        "service": "Express",
        "weight": "2.4 kg",
        "sender": {
            "name": "Northwind Studio",
            "address": "14 Bridgewater Street\nManchester M15 4RN\nUnited Kingdom"
        },
        "recipient": {
            "name": "Fabrikam Ltd",
            "address": "9 Peveril Road\nSheffield S11 7AQ\nUnited Kingdom"
        },
        "reference": "PO-99213",
        "tracking_number": "NW 4821 7734 GB",
        "barcode_url": "https://cdn.example.com/barcodes/NW48217734GB.png"
    },
    "options": {
        "format": "A6",
        "margin": {
            "top": "0",
            "right": "0",
            "bottom": "0",
            "left": "0"
        },
        "print_background": true,
        "wait_for": "networkidle"
    }
},
)
response.raise_for_status()
print(response.json()["output_url"])