CASE STUDY · FORGE · CUSTOM APPLICATION
From 3PL chaos to a single screen that runs the warehouse floor
A high-volume Shopify store had outgrown every off-the-shelf fulfilment tool. Picklists were printed and hand-marked. Label errors were a daily occurrence. We built a custom fulfilment application that handles everything end-to-end, processing over $500k in annual revenue.
The problem
The merchant was processing hundreds of orders a week across multiple carriers and a third-party logistics (3PL) provider. Their fulfilment "system" was a combination of Shopify's built-in order screen, a spreadsheet that tracked what had been picked, and a browser tab open to each carrier's label portal.
Picking errors were caught on the warehouse floor, sometimes. Label errors were caught by customers, usually in a one-star review. The 3PL sent a monthly charges spreadsheet that took a day to reconcile against what Shopify said had shipped.
They'd tried three different fulfilment SaaS tools. Each one had a different assumption about how orders should flow, and none of them matched how this particular operation worked: a mix of their own stock, 3PL-held stock, and vendor drop-ship that needed different routing logic depending on the SKU.
What "fixed" looks like
A single internal web application, accessible on the warehouse floor from any device, that replaces every tab, every spreadsheet, and every manual step in the fulfilment process:
- Orders arrive from Shopify in real time via webhook. The app routes each line item to the correct fulfilment method based on SKU-level rules.
- Warehouse staff see a pick-and-pack screen with exactly what to pick and in what order. No printed lists, no handwriting.
- Labels are generated automatically via the correct carrier API and printed in one click. No browser tabs, no copy-paste.
- 3PL charges are pulled via API daily and matched against shipped orders automatically. Reconciliation goes from a day to a glance.
- Shopify is updated in real time: tracking numbers, fulfilment status, and inventory levels.
How we built it
The application is a TypeScript/Node.js backend with a lightweight browser-based frontend. It connects to Shopify via their Webhooks and Admin API, to the 3PL via their REST API, and to each carrier's label generation API directly.
The routing logic is rule-based and configurable by the client without a code deploy: carrier, weight thresholds, destination zones, and fulfilment method are all managed through a simple admin screen.
// rules are configured in the admin UI, not hardcoded async function routeOrder(order: Order): Promise<Label> { const rules = await db.rules.findActive({ merchantId: order.merchantId }); const match = rules .sort((a, b) => a.priority - b.priority) .find(r => r.maxWeightGrams >= order.totalGrams && r.destinationZones.includes(order.state) && r.skuTags.every(t => order.tags.includes(t)) ); if (!match) { await alertOps(`No carrier matched for ${order.name}`); throw new UnroutableOrderError(order.name); } return match.carrier.createLabel(order); }
// HMAC-verified Shopify webhook handler app.post("/hooks/shopify/orders/create", async (req, res) => { verifyShopifyHmac(req); // throws 401 if invalid res.sendStatus(200); // acknowledge immediately // enqueue for async processing: never block the webhook await queue.add("fulfil-order", { orderId: req.body.id, shop: req.headers["x-shopify-shop-domain"] }); });
The edge cases that bite
A single order can contain items fulfilled by different methods: own-warehouse, 3PL, and drop-ship on the same order. The app splits these into separate fulfilment batches, each with their own label and tracking, and surfaces them to the customer as separate shipments with individual tracking numbers. Shopify's API supports this natively; most off-the-shelf tools don't.
Carrier label APIs go down, usually at the worst possible time. The app queues label generation with automatic retry and exponential backoff. Operations staff see a status indicator when a carrier is degraded, and can manually route affected orders to an alternate carrier from the admin screen without touching code.
3PL charge feeds don't always match what you think was shipped: items held, redelivery attempts, and correction credits show up days later. The reconciliation engine holds charges in a "pending" state until they've been matched to a shipment, and flags anything unmatched after 14 days for manual review. The old spreadsheet didn't do this; charges were quietly absorbed.
What it'd take for you
If you're running a Shopify store at meaningful volume and your fulfilment process involves more than one carrier or more than one fulfilment location, the off-the-shelf tools will start to show their seams. The routing rules and edge cases are always specific to how your operation actually works.
A project like this typically scopes as a Forge engagement: fixed price, 8–16 weeks depending on the complexity of your carrier mix and existing systems. The right starting point is a 30-minute scoping call where we understand your order volume, your carriers, and what's breaking today.
Does this sound like your operation?
30-minute scoping call, free. We'll tell you whether custom is the right call or whether there's an off-the-shelf option we'd recommend instead.
Book a scoping call