Integration recipe

Print Shopify orders without anyone opening a browser.

Subscribe to an order webhook, build the packing slip or fetch the label, and send it to the printer at the bench that will pack it. About twenty lines in a function you already have.

The recipe

Webhook in, paper out.

Shopify already tells you when an order is paid or a fulfillment is created. That event is the trigger.

01

Subscribe to the webhook

orders/paid for pick-and-pack, or fulfillments/create if you print at the point of fulfillment. Point it at your own endpoint.

topic: orders/paid
02

Build the document

Render your packing slip as a PDF, or take the carrier's ZPL if you are printing a shipping label. Base64-encode either one.

contentType: pdf_base64
03

Send it to the right bench

Map the order's location to a printer ID you store, and POST the job with an idempotency key derived from the order ID.

POST /v1/print-jobs
webhooks/orders-paid.ts
import RocketPrint from "@rocketprint/node";

const rocketprint = new RocketPrint({ apiKey: process.env.ROCKETPRINT_KEY });

// Your own mapping — Shopify location ID → RocketPrint printer ID.
const SLIP_PRINTER = {
  "gid://shopify/Location/1234": "6a4738f7462183c7f5d70598",
};

export async function onOrderPaid(order) {
  const pdf = await renderPackingSlip(order);          // your existing renderer

  await rocketprint.printJobs.create({
    printerId: SLIP_PRINTER[order.location_id],
    title: `Packing slip ${order.name}`,
    contentType: "pdf_base64",
    content: pdf.toString("base64"),
    source: "shopify",
  }, {
    // Shopify re-delivers webhooks; this makes that harmless.
    idempotencyKey: `shopify-order-${order.id}-slip`,
  });
}

Practical notes

Things worth knowing first.

Packing slips are PDFs; labels should be ZPL

A packing slip through the station's driver is fine. A shipping label is not — ask your carrier for ZPL and send it as raw_base64 so the barcode is generated by the printer rather than rasterized on the way.

Shopify retries webhooks

That is a feature, and idempotency keys make it a harmless one. Derive the key from the order or fulfillment ID and a duplicate delivery returns the original job.

Multi-location stores

Keep your own map from Shopify location to printer ID. Adding a warehouse becomes a row in that map plus an agent install, not a code change.

A sleeping bench machine is fine

If the station is offline when the webhook fires, the job queues and prints on reconnect. Your webhook handler still returns 200 immediately. How queueing works →

Questions

Shopify-specific questions.

Is this a Shopify app I install?

No. This is a recipe for your own backend or serverless function. You subscribe to a Shopify webhook, build the document, and POST it to RocketPrint. Nothing is installed into your storefront.

Where does the label come from?

From whichever carrier or shipping platform you already buy postage through. Shopify tells you an order is ready; your carrier gives you the label; RocketPrint puts it on paper.

Can different locations print to different printers?

Yes. Shopify's location on the order maps to a printer ID you store yourself. Routing is a field in the print request.

How do we avoid printing twice when Shopify re-delivers a webhook?

Shopify retries webhooks, so derive your Idempotency-Key from the order or fulfillment ID. A re-delivered webhook then returns the original print job instead of printing a second slip.

Try it on one order

Wire one webhook to one printer.

Install the agent at a bench, create a key, and print the next order that comes in.