Buy postage as ZPL
Ask for the ZPL format when you buy the shipment, so the thermal printer gets its own language instead of a redrawn page.
label_format: ZPLIntegration recipe
EasyPost gives you a label the moment you buy postage. We put it on the thermal printer at the bench packing that order — no browser, no shared folder, no watcher script.
The recipe
Ask for ZPL, fetch the bytes in your backend, and send them to the bench printer.
Ask for the ZPL format when you buy the shipment, so the thermal printer gets its own language instead of a redrawn page.
label_format: ZPLEasyPost returns a URL. Fetch it on your server, where your credentials already are, and base64-encode the bytes.
fetch(label_zpl_url)Send the encoded ZPL to the printer ID you store for that bench, keyed on the shipment ID so retries are safe.
POST /v1/print-jobsconst RocketPrint = require("rocketprint");
const rocketprint = new RocketPrint(process.env.ROCKETPRINT_KEY);
export async function shipOrder(order, bench) {
// 1. Buy postage, asking for ZPL because the bench has a thermal printer.
const shipment = await easypost.Shipment.create({ /* to, from, parcel */ });
const bought = await shipment.buy(shipment.lowestRate(), { label_format: "ZPL" });
// 2. Fetch the label server-side. RocketPrint never fetches URLs for you.
const zpl = await fetch(bought.postage_label.label_zpl_url).then((r) => r.arrayBuffer());
// 3. Print it where the box actually is.
const job = await rocketprint.printJobs.create({
printerId: bench.printerId,
title: `Label ${bought.tracking_code}`,
contentType: "raw_base64",
content: Buffer.from(zpl).toString("base64"),
source: "easypost",
}, {
idempotencyKey: `easypost-${bought.id}-${bench.id}`,
});
return { trackingCode: bought.tracking_code, printJobId: job.id };
}Practical notes
We could accept the label URL, but then a computer inside your warehouse would be making web requests to addresses your backend supplied. Fetching it yourself keeps that boundary where it belongs. Read the security model →
Store both against the shipment. When support asks about a parcel, one lookup answers both "where is it" and "did the label print."
Include the bench or printer in the key. A key based only on the shipment will return the first job if you deliberately print the same label in two places.
A failed job tells you why, and your postage is unaffected. Send the same bytes again once the printer is back.
Questions
No, and that is deliberate. We do not fetch label URLs, so a computer in your warehouse never makes web requests to whatever address was passed in. Fetch the label in your own backend, where your credentials already live, and send us the bytes.
Ask EasyPost for ZPL when it is going to a thermal printer. A PDF prints through that computer's driver, which decides scaling — workable, but less predictable for a 4×6 label.
Send two jobs with different printer IDs. Use a different idempotency key for each bench, or the second request will return the first job instead of printing.
The job is marked failed with the reason attached, and your postage stays bought. Alert on failed jobs and send it again — the label has not changed.
Next shipment
Install the Station app at one bench, create a key, and add three lines after your buy call.