Requex.me LogoRequex.me

Documentation

Browse by section

Keep all guides, tool docs, automation recipes, and comparison pages in one navigable place.

Docs Home
Docs

Foundation docs for getting started fast, understanding key terms, and tracking what has changed.

Guides

Start with fundamentals, then move into provider-specific webhook testing and production hardening.

Tool Docs

These pages explain what each tool does, when to use it, and how it fits into a webhook debugging workflow.

Automation Docs

Use these setup guides when you want forwarding rules, custom responses, security checks, or multi-destination fanout.

Compare

Use these pages to compare developer workflows, pricing tradeoffs, and feature differences between webhook tools.

3PL Webhook Integration Guide

How to capture and verify 3PL fulfillment webhooks from Shippo, EasyPost, and ShipBob. Handle delivery guarantees and idempotency.

Editorially reviewed by the Requex team12 min readAbout the product

Quick Answer

3PL webhooks notify your backend when shipments are created, picked, packed, shipped, or delivered. Shippo and EasyPost sign webhooks with HMAC-SHA256; ShipBob includes a signature header. Test locally with Requex.me (no tunneling needed). Key challenges: schema mapping (EDI X12), 24-48h delivery guarantees, idempotency (webhook_id persists 3 days), and exponential backoff retries.

Why 3PL Webhooks Matter for Ecommerce

Third-party logistics providers (Shippo, EasyPost, ShipBob) manage fulfillment after you hand off an order. Webhooks keep your system in sync: when the 3PL picks and ships, you need to know immediately to update order status, notify customers, and trigger downstream workflows (email campaigns, inventory adjustments, return flows).

Without webhooks, you'd poll the 3PL API constantly. With webhooks, events arrive in real-time (or with a 24-48h SLA for some providers). This enables:

  • Real-time tracking number sync to order confirmation emails
  • Automated return label generation when a shipment is returned
  • Inventory deallocation once the 3PL confirms pick
  • Customer notifications ("Your order shipped!" → "Out for delivery" → "Delivered")
  • Chargeback prevention by confirming delivery timestamps

Key 3PL Webhook Events

ProviderEventsUse Case
Shipposhipment.created, label.created, track_updatedLabel generation, pickup scheduling, tracking updates
EasyPostshipment.updated, tracker.updated, batch.createdBulk shipping, carrier selection, delivery confirmation
ShipBobfulfillment.created, fulfillment.shipped, fulfillment.deliveredPick/pack/ship workflow, delivery proof, return processing

Testing 3PL Webhooks with Requex.me

Before deploying, test webhook payloads locally with a free endpoint:

  1. Visit Requex.me and copy your unique webhook URL.
  2. In your 3PL dashboard, register the webhook endpoint. Example: https://your-id.requex.me
  3. In your 3PL admin, create a test shipment or label.
  4. Watch the webhook payload appear instantly in your Requex dashboard.
  5. Inspect the payload, signature header, and event type. Verify your webhook handler can parse it.

Requex captures and displays the raw HTTP request including headers and body—useful for debugging signature verification before deploying to production.

Four Common 3PL Webhook Challenges

1. Schema Mapping (EDI X12/EDIFACT)

3PLs often use EDI (Electronic Data Interchange) formats like X12 or EDIFACT for integration. These are complex, hierarchical formats with fixed-width fields. Shippo and EasyPost expose webhooks in JSON, but the underlying data model differs: Shippo uses address_from/address_to; EasyPost uses from_address/to_address.

Fix: Map webhook fields to your internal schema before saving. Use a library like joi or zod to validate and transform.

2. Delivery Guarantees & Sync Delays

3PLs typically guarantee delivery within 24-48 hours. If your server is down, the 3PL may retry with exponential backoff (1 min, 5 min, 30 min, 2h, etc.). Shippo retries 10 times over 3 days. During this window, webhook_id remains the same—critical for idempotency.

Fix: Store webhook_id in your database. When a webhook arrives, check if you've already processed it. If yes, return 200 without re-processing. This prevents duplicate order status updates.

3. Idempotency & Webhook ID Expiry

The webhook_id (or event_id) in the payload is your idempotency key. However, 3PLs may only guarantee this ID for 3 days. After 3 days, if the same webhook is retried, it may come with a new webhook_id. This creates a blind spot: you can't reliably deduplicate after 3 days.

Fix: Use both webhook_id AND the business key (shipment_id + event_type) for idempotency. Query: "Do we have a record of this shipment_id being shipped?" instead of just "Is webhook_id X in our log?"

4. Signature Verification & Secret Management

Shippo and EasyPost both use HMAC-SHA256 to sign webhooks. ShipBob includes a signature header. The challenge: where do you store the webhook signing secret? Typically, the 3PL dashboard shows it once during setup. If you lose it, you can't verify new webhooks until you rotate.

Fix: Store the secret in your backend environment as SHIPPO_WEBHOOK_SECRET, never in code. Use a secrets manager (AWS Secrets Manager, Vault, etc.). Before rotating, add the new secret to your verification logic temporarily.

3PL Webhook Signature Verification

All major 3PLs sign their webhooks using HMAC-SHA256. Verify the signature before processing:

// Node.js / Express middleware for 3PL signature verification
const crypto = require('crypto');

function verify3PLSignature(req, signatureHeader, secret, algorithm = 'sha256') {
    const hash = crypto
        .createHmac(algorithm, secret)
        .update(req.rawBody) // Raw body BEFORE JSON parsing
        .digest('hex');

    return crypto.timingSafeEqual(
        Buffer.from(signatureHeader),
        Buffer.from(hash)
    );
}

// Shippo example
app.post('/webhooks/shippo', express.raw({type: 'application/json'}), (req, res) => {
    const signature = req.headers['x-shippo-signature'];

    if (!verify3PLSignature(req, signature, process.env.SHIPPO_WEBHOOK_SECRET)) {
        return res.status(401).json({ error: 'Invalid signature' });
    }

    const payload = JSON.parse(req.body);
    const webhookId = payload.id;

    // Check idempotency: have we processed this webhook_id?
    const existing = await Webhook.findOne({ webhookId });
    if (existing) return res.status(200).json({ received: true });

    // Save webhook for idempotency
    await Webhook.create({ webhookId, event: payload.event, payload });

    // Process shipment update
    if (payload.event === 'track_updated') {
        const { tracking_status } = payload.data;
        await Order.update({ orderId: payload.data.order_id }, { trackingStatus: tracking_status });
    }

    res.status(200).json({ received: true });
});

Data Flow: Order → 3PL → Webhook → Your Fulfillment Status

Here's how a typical order flows through a 3PL integration:

  1. Order placed: Customer buys on your storefront. Order created with items and shipping address.
  2. Send to 3PL: Your backend calls POST /shipments to Shippo/EasyPost with order details. 3PL responds with shipment_id.
  3. 3PL picks & packs: Warehouse receives the order, picks items, packs box. Status progresses: pending → label_generated → picked → packed.
  4. Label created webhook: 3PL sends webhook label.created with tracking number.
  5. Your webhook handler: Receives webhook, verifies signature, stores tracking number, updates order status to "shipped".
  6. Customer notified: Your email system triggers "order shipped" email with tracking link.
  7. Tracking updates: As package moves, carrier sends events to 3PL. 3PL forwards track_updated webhooks.
  8. Final delivery: track_updated event with status "delivered" triggers final customer notification and closes fulfillment loop.

See Also

For broader integration patterns, see Shopify API integrations and Shopify alternatives for developers.

Start Testing Webhooks Now

Generate your unique URL and test webhooks instantly. Free, no signup.

Open Webhook Tester →