Docs menu

Webhooks

Subscribe an HTTPS endpoint and Darb POSTs a signed JSON delivery when work completes — so you can react to route and campaign events instead of polling. Every delivery is signed withStandard Webhooks headers you verify with an off-the-shelf library.

How delivery works

When an event fires, Darb sends an HTTP POST to your subscribed URL. The body is a JSON envelope — { type, timestamp, data } — and the request carries four Standard Webhooks headers (below). Retries reuse the same webhook-id, so treat deliveries as at-least-once and dedupe by webhook-id. Payloads are deliberately thin: resource IDs and a coarse status only — never a coordinate, phone number, or customer name (so the 30-day location purge can't be defeated through this side-channel).

Events

There are exactly three events. Each sample below shows the thin data payload for that event.

route.optimized

A route finished optimizing. status is the terminal route status (e.g.completed); route_id is the route you created.

json
{
  "route_id": "r_0d3f8c21",
  "status": "completed"
}

location.collected

A campaign contact shared their location. Carries the campaign_id and thecontact_id only — never the collected coordinate or the phone number (fetch the resource if you need more).

json
{
  "campaign_id": "c_9a1b7e40",
  "contact_id": "ct_44f0a2d1"
}

campaign.completed

A collection campaign reached a terminal state. route_id is present only when the completed campaign produced an optimized route.

json
{
  "campaign_id": "c_9a1b7e40",
  "status": "completed",
  "route_id": "r_0d3f8c21"
}

Delivery format

Each delivery body is the full envelope wrapping the data above. For example, aroute.optimized delivery:

json
{
  "type": "route.optimized",
  "timestamp": "2026-07-14T00:00:00+00:00",
  "data": {
    "route_id": "r_0d3f8c21",
    "status": "completed"
  }
}

On the wire the body is serialized compact with sorted keys — that exact byte string is what the signature is computed over, so verify against the raw received body and never a re-serialized copy. The request carries these headers:

http
POST /your/webhook/endpoint HTTP/1.1
content-type: application/json
webhook-id: 550e8400-e29b-41d4-a716-446655440000
webhook-timestamp: 1783987200
webhook-signature: v1,K5oyc4Xr8m2xQ0y1x2s3D4e5F6g7H8i9J0kL1m2N3o=
  • webhook-id — the event's UUID, stable across retries; dedupe on it.
  • webhook-timestamp — epoch seconds; verification enforces a tolerance window.
  • webhook-signature — the signature, formatted v1,<base64>.
  • content-type — always application/json.

The signing secret

Each subscription has its own signing secret in the form whsec_ followed by standard base64. It is shown once, when you create the subscription — store it securely; it is never shown again (regenerate it if lost). The secret is the HMAC key your verification library uses below.

Verifying a delivery

Verify every delivery before trusting it. Do not hand-roll an HMAC check — use the off-the-shelf standardwebhooks library. Pass the raw received body and the threewebhook-* headers; a bad signature (or a stale timestamp) raises, a good one returns cleanly. Python is shown first, Node second — the call is identical:Webhook(secret).verify(body, headers).

python
# pip install standardwebhooks
from standardwebhooks import Webhook

# secret: the whsec_... value shown ONCE when you created the subscription
wh = Webhook(secret)

# body: the EXACT received request body (raw bytes/string) — do NOT re-serialize it
wh.verify(body, {
    "webhook-id": headers["webhook-id"],
    "webhook-timestamp": headers["webhook-timestamp"],
    "webhook-signature": headers["webhook-signature"],
})
javascript
// npm i standardwebhooks
import { Webhook } from "standardwebhooks";

// secret: the whsec_... value shown ONCE when you created the subscription
const wh = new Webhook(secret);

// body: the EXACT received request body (raw string) — do NOT re-serialize it
wh.verify(body, {
  "webhook-id": headers["webhook-id"],
  "webhook-timestamp": headers["webhook-timestamp"],
  "webhook-signature": headers["webhook-signature"],
});

standardwebhooks ships verifiers for 11+ languages. Reference implementations and docs: standard-webhooks on GitHub.