← Case studies

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.

Shopify · custom fulfilment app · 3PL integration · carrier API · fixed scope engagement

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:

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.

Shopify order Conduit fulfilment app 3PL API Carrier label Shopify tracking update

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.

// order routing: carrier selection by weight + zone
// 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);
}
// shopify webhook → fulfilment queue
// 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

// EDGE CASE: split fulfilment

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.

// EDGE CASE: carrier API downtime

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.

// EDGE CASE: 3PL charge reconciliation drift

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