Gareth Wilson Gareth Wilson

Guide to ShipBob Webhooks: Features and Best Practices

Published


ShipBob webhooks notify your systems about fulfillment activity: an order ships, a shipment is delivered, tracking updates, a return is created. If you're building on ShipBob's fulfillment API, webhooks are how you react in real time without polling.

This guide covers how ShipBob webhooks work, the topics you'll subscribe to, how to verify signatures (ShipBob uses the Standard Webhooks format), the retry behavior, and the best practices for production.

What are ShipBob webhooks?

ShipBob webhooks are HTTP POSTs delivered to a URL you subscribe. The signature scheme is the Standard Webhooks / Svix format (the docs don't name it, but the fields are identical): webhook-id, webhook-timestamp, and webhook-signature headers.

Because it's Standard Webhooks, you verify with the familiar HMAC-over-id.timestamp.body scheme, using the Svix or standardwebhooks libraries.

ShipBob webhook features

FeatureDetails
ConfigurationPOST /2026-01/webhook with { topics: [...], url }
Scopeswebhooks_write plus the read scope per topic (orders_read, fulfillments_read, ...)
Signature headerswebhook-id, webhook-timestamp, webhook-signature
Signature schemebase64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{body}
Signing secretwhsec_<base64> (strip the prefix, base64-decode the remainder)
Retriesimmediately, 5s, 5m, 30m, 2h, 5h, 10h, 10h
Acknowledgement2xx within ~15s
Auto-disableAfter ~5 days of failures
SDKNone (use svix / standardwebhooks)

Common topics

ShipBob's current topics use dotted names:

TopicFires when
order.shippedAn order ships
order.shipment.deliveredA shipment is delivered
order.shipment.tracking.updatedTracking updates for a shipment
order.shipment.exceptionA shipment hits an exception
return.createdA return is created
wro.createdA warehouse receiving order is created

Legacy 1.0/2.0 topics used underscores (order_shipped, shipment_delivered); the current API uses the dotted names above. Subscribe to the topics you process, and consult ShipBob's webhook reference for the full list.

Setting up ShipBob webhooks

Subscribe via POST /2026-01/webhook with { topics: [...], url }. You need the webhooks_write scope plus the read scope for each topic (orders_read, fulfillments_read, returns_read, receiving_read, billing_read). The 2026-01 date-versioned path is current; the legacy 2.0 API used POST /2.0/webhook with { topic, subscription_url }.

Securing ShipBob webhooks

Each delivery is signed with HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{body}, keyed with the base64-decoded portion of your whsec_ secret; webhook-signature holds space-delimited v1,<sig> entries. There's no official ShipBob SDK, so use the svix (or standardwebhooks) library:

const { Webhook } = require("svix");

const wh = new Webhook(process.env.SHIPBOB_WEBHOOK_SECRET); // whsec_...

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const payload = wh.verify(req.body, {
      "webhook-id": req.headers["webhook-id"],
      "webhook-timestamp": req.headers["webhook-timestamp"],
      "webhook-signature": req.headers["webhook-signature"],
    });
    res.sendStatus(200); // acknowledge within ~15s
    processQueue.add(payload); // process asynchronously
  } catch {
    res.sendStatus(400); // verification failed
  }
});

The same check in Python:

from standardwebhooks import Webhook

wh = Webhook(os.environ["SHIPBOB_WEBHOOK_SECRET"])  # whsec_...


@app.post("/webhook")
def webhook():
    try:
        payload = wh.verify(request.get_data(), dict(request.headers))
    except Exception:
        return "", 400
    # process asynchronously
    return "", 200

Verify against the raw, unmodified request body.

ShipBob webhook limitations and pain points

Standard Webhooks mechanics

The Problem: The whsec_ secret must be base64-decoded (after the prefix), the signature is over id.timestamp.body, and rotation yields multiple v1,<sig> entries. Hand-rolling any of it wrong fails verification.

Why It Happens: These are Standard Webhooks/Svix details.

Workarounds:

  • Use the svix or standardwebhooks library rather than implementing the HMAC yourself.

How Hookdeck Can Help: Hookdeck verifies Standard Webhooks signatures at the edge, so your app receives pre-verified events. See our guide to Svix webhooks.

Dotted vs underscore topics across versions

The Problem: Current topics are dotted (order.shipped); legacy 1.0/2.0 used underscores (order_shipped). Subscribing with the wrong form (or on the wrong API version) means you receive nothing.

Why It Happens: ShipBob changed the topic naming and API path across versions.

Workarounds:

  • Use the 2026-01 API with dotted topics, and confirm the exact topic strings against the current reference.

How Hookdeck Can Help: Hookdeck's filters route on the fields you actually receive, so version differences are handled in one place.

The retry ladder and auto-disable

The Problem: Failed deliveries retry on a fixed ladder (immediately, 5s, 5m, 30m, 2h, 5h, 10h, 10h), and the subscription auto-disables after ~5 days of failures. Duplicates arrive along the way.

Why It Happens: At-least-once delivery plus pruning of persistently failing endpoints.

Workarounds:

  • Acknowledge with a 2xx within ~15s so transient issues don't accumulate; dedupe on webhook-id; monitor and re-enable if disabled.

How Hookdeck Can Help: Hookdeck accepts every delivery, deduplicates, and retries to your downstream on a schedule you control, so the ladder isn't your only safety net and the subscription stays active. See our guide to webhook idempotency.

Best practices

Verify with a Standard Webhooks library

Use svix / standardwebhooks to handle the base64 secret, the id.timestamp.body construction, and rotation, over the raw body.

Use the current dotted topics

Subscribe on the 2026-01 API with dotted topic names.

Acknowledge within ~15 seconds, process asynchronously

Return 2xx quickly and defer work to a queue. See why to process webhooks asynchronously.

Dedupe on webhook-id and monitor status

Dedupe so retries don't double-process, and watch for auto-disable after sustained failures.

Make ShipBob webhooks production-ready

Hookdeck verifies the Standard Webhooks signature, deduplicates, and durably queues every fulfillment event

Conclusion

ShipBob webhooks use the Standard Webhooks format: verify the webhook-signature over id.timestamp.body with the base64-decoded whsec_ secret, subscribe with the current dotted topics on the 2026-01 API, and handle the retry ladder plus ~5-day auto-disable. With no official SDK, the svix / standardwebhooks libraries do the verification.

Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique fulfillment events.

Get started with Hookdeck for free and handle ShipBob webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.