Automated order fulfilment cut processing time by 80%
A growing DTC brand was manually processing 300+ orders per day across three sales channels. Fulfilment delays, mis-picks, and a burnt-out ops team were eating into margins. We built a unified, zero-touch pipeline that handles every order automatically, from receipt to despatch confirmation.
Key Results
- 80% reduction in order processing time
- 99.2% order accuracy rate
- 14 hours/week returned to the ops team
Stack
The Situation
By the time we first spoke to this client, their ops team had already built a system. It was just a human one.
Every morning started with a ritual: export overnight orders from Shopify, pull in the same period's Amazon Seller Central CSV, check the wholesale portal for B2B batch orders, and then manually cross-reference all three against live inventory tracked in Airtable. From there, fulfilment details were typed into their 3PL's web portal, row by row. Confirmation emails were sent by hand.
At 50 orders a day, it was slow but manageable. At 300+, and growing 15% month over month, it was a full-time job that two people were doing badly.
Errors had become a weekly occurrence. A customer would receive the wrong size. A high-value wholesale order would be partially fulfilled with no automatic notification to the buyer. Inventory counts drifted because corrections weren't flowing back to Airtable when returns were processed.
The business was scaling. The infrastructure wasn't.
Pipeline Architecture
Before writing a single workflow, we mapped every touchpoint where a human was making a decision that a rule could make instead.
flowchart TD
A([🛒 Order Placed]) --> B{Channel Router}
B -->|Shopify webhook| C[Shopify Module]
B -->|Amazon polling| D[Amazon SP-API Module]
B -->|Wholesale form| E[Typeform → Airtable]
C --> F[Order Normaliser]
D --> F
E --> F
F --> G{Inventory Check\nAirtable}
G -->|In stock| H[Format 3PL Payload]
G -->|Low stock| I[⚠️ Slack Alert\nOps Channel]
G -->|Out of stock| J[Auto-notify Customer\n+ Flag for Review]
I --> H
H --> K[Submit to 3PL API]
K --> L{3PL Response}
L -->|Accepted| M[Update Airtable\nDeduct Inventory]
L -->|Error| N[🚨 Escalation Alert\nSlack + Email]
M --> O[Push Tracking\nBack to Channel]
O --> P[Send Customer\nConfirmation Email]
P --> Q([✅ Order Complete])
The key insight was that the ops team didn't need to be removed from the process. They needed to be elevated out of the repetitive parts so they could focus on the 2% of orders that genuinely need human judgement.
What We Built
The pipeline is orchestrated in Make, using a combination of webhooks (for Shopify), scheduled polling (for Amazon, which doesn't support outbound webhooks reliably), and Airtable automations for the wholesale channel.
Channel Ingestion
Each sales channel sends order data in a different format. Our first module is an order normaliser that maps every channel's schema into a single internal object before anything else runs.
// Normalised internal order object — consistent regardless of source channel
{
"order_id": "BF-2025-08741",
"source_channel": "shopify", // "shopify" | "amazon" | "wholesale"
"created_at": "2025-01-14T09:22:11Z",
"customer": {
"name": "Sarah Thompson",
"email": "sarah@example.com",
"shipping_address": {
"line1": "14 Maple Street",
"city": "Bristol",
"postcode": "BS1 4QA",
"country": "GB"
}
},
"line_items": [
{
"sku": "HOODIE-NAVY-M", // Normalised SKU — cleaned from channel-specific format
"qty": 2,
"unit_price_gbp": 45.00
}
],
"order_tags": ["gift", "express"], // Preserved for downstream routing logic
"requires_gift_packing": true // Derived from tag parsing
}
Inventory Validation
Before any fulfilment request is sent, the pipeline checks live stock levels in Airtable. This is where most of the edge cases live.
// Airtable inventory lookup response
{
"sku": "HOODIE-NAVY-M",
"available_qty": 47,
"reserved_qty": 3, // Already committed to pending orders
"reorder_threshold": 10,
"warehouse_location": "BIN-C14",
"low_stock_alert_sent": false // Prevents duplicate Slack pings
}
If available minus reserved drops below the threshold for any line item, the Slack alert fires to the ops channel before fulfilment is attempted. The team can then pull from a backup location or contact the supplier, rather than discovering a mis-pick after the fact.
3PL Integration
The 3PL expects a very specific XML payload (a legacy integration they haven't modernised). Make handles the transformation:
// Input to Make's XML formatter module
{
"despatch_request": {
"client_ref": "BF-2025-08741",
"priority": "standard", // "standard" | "express" | "same-day"
"packing_instruction": "gift-wrap", // Derived from order_tags
"lines": [
{
"sku": "HOODIE-NAVY-M",
"qty": 2,
"bin": "BIN-C14" // Passed in from inventory lookup
}
],
"delivery": {
"name": "Sarah Thompson",
"address1": "14 Maple Street",
"city": "Bristol",
"postcode": "BS1 4QA",
"country_code": "GB",
"carrier": "ROYAL_MAIL_TRACKED48" // Carrier selection logic based on postcode + weight
}
}
}
Error Handling
Every step in the pipeline has explicit failure handling. Nothing silently swallows an error.
flowchart LR
A[3PL API Call] --> B{HTTP Status}
B -->|200 OK| C[Parse Response\n& Continue]
B -->|4xx Client Error| D[Log Full Request\n& Response to Airtable]
B -->|5xx Server Error| E{Retry Logic}
B -->|Timeout| E
E -->|Attempt 1 of 3\nWait 30s| A
E -->|Attempt 2 of 3\nWait 2m| A
E -->|Attempt 3 of 3\nWait 5m| A
E -->|All retries failed| F[🚨 Slack Escalation\nwith Order ID + Error Detail]
D --> G[🔔 Ops Alert\nManual Review Required]
F --> G
The Slack alert on failure includes the full internal order ID, the channel it came from, the exact error returned by the 3PL, and a direct deep-link into the Airtable record so the ops team can action it without hunting for context.
Inventory Sync Loop
One problem we solved that hadn't been explicitly requested: inventory levels were drifting because returns and manual adjustments weren't flowing back from the 3PL. We built a nightly reconciliation job that pulls the previous day's confirmed despatches and returns from the 3PL, diffs them against Airtable, and applies corrections.
flowchart TD
A([⏰ Nightly Reconciliation\nRuns at 02:00 UTC]) --> B[Pull Despatch Confirmations\nfrom 3PL API]
A --> C[Pull Return Receipts\nfrom 3PL API]
B --> D[Compare vs\nAirtable Expected]
C --> D
D --> E{Discrepancy\nDetected?}
E -->|No| F([✅ All Good — Log Run])
E -->|Yes| G[Calculate Delta]
G --> H[Apply Correction\nto Airtable]
H --> I[Log Correction with Reason]
I --> J[Weekly Summary\nEmail to Ops Manager]
The Results
Within the first week of going live, the ops team's morning ritual was gone. Within 60 days:
- Processing time dropped by 80%. From an average of 4 minutes per order to under 50 seconds end-to-end, including confirmation email.
- Order accuracy improved to 99.2%. Errors caused by copy-paste fatigue and misread spreadsheet rows virtually disappeared.
- 14 hours per week returned to ops, time now spent on supplier relationships, returns management, and quality control.
- Inventory drift eliminated. The nightly reconciliation caught corrections within 24 hours rather than discovering them during a stock-take.
The client has since scaled order volume by a further 40% without adding headcount to the fulfilment function.
What We Learned
The biggest challenge wasn't building the automation. It was untangling three years of "we'll fix it later" in the Airtable inventory base. Duplicate SKUs, inconsistent naming conventions, fields that different people used for different purposes.
We spent the first week doing data archaeology before a single workflow was built. It's not glamorous work, but automation built on bad data just fails faster and at higher volume. Cleaning the foundation first is always the right call.
The second lesson: always build the error escalation path before you build the happy path. The ops team's trust in the system came from seeing a Slack alert fire on a real 3PL timeout during UAT, and watching the retry logic kick in, succeed on the second attempt, and resolve without human intervention. That single moment sold the handover.
Want results like these?
Book a free discovery call and we'll map out what's possible.