Skip to main content
A webhook is an HTTP request that HaulStow sends to your server. Instead of asking “has this delivery changed?” every 10 seconds, your server receives an update when the change happens.
Start with polling if your backend is not publicly reachable yet. Add webhooks before production when possible.

Set up your first webhook

  1. Create a public HTTPS POST endpoint in your backend, for example https://api.example.com/webhooks/haulstow.
  2. In the HaulStow developer portal, open your application and add a webhook endpoint.
  3. Choose the test environment and the events you want.
  4. Copy the signing secret beginning with whsec_. It is shown only once.
  5. Save the secret in your server-side secret manager.
  6. Use the portal’s test button and confirm that your endpoint returns a 2xx response.
A webhook signing secret is different from an API key. The API key authenticates requests you send to HaulStow. The webhook secret verifies requests HaulStow sends to you. Never put either secret in frontend code.

Events

The useful delivery snapshot is inside data.delivery. Save the top-level event id. HaulStow may send the same event more than once, so use this ID to detect duplicates. The sequence number increases for one delivery. If you already applied sequence 5, do not move your local status backwards when sequence 4 arrives late.

Verify the signature

Each request includes:
The signature proves that the request came from someone who knows your webhook secret and that the body was not changed in transit. You must verify the signature against the exact bytes received from the network. Verify before parsing JSON. Parsing and then re-encoding JSON can change spaces or key order and make a valid signature fail.
Node.js
Here is a minimal Express route using that function:
Node.js
Register the raw-body parser on the webhook route before a global JSON parser. In frameworks such as Next.js, NestJS, Laravel, Django, or Rails, use the framework’s documented raw-request-body feature.
Also check that the timestamp is no more than five minutes old. This reduces replay attacks. Compare HMAC values with a constant-time function such as Node’s timingSafeEqual. During secret rotation, a callback may contain two v1 values for 24 hours. Keep the previous secret during that overlap and accept the request when either the current or previous secret validates its matching signature.

Delivery and retries

HaulStow delivers webhooks at least once, which means duplicates are normal and your handler must be safe when they happen. Return 2xx only after you have saved the event or placed it on a durable queue. Do not wait for slow work such as sending email or updating several services. Network errors, timeouts, 408, 425, 429, and 5xx responses retry. Other 4xx responses stop automatic retries and require a manual replay from the portal. Retries occur immediately, then at approximately 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours, and 24 hours, with jitter. Retry-After is honored for 429 and 503 when it fits within the retry window. Perform slow work asynchronously after persisting the event. A manual replay keeps the event ID but receives a new Haulstow-Delivery-Id.

Debugging checklist

If no webhook arrives:
  1. Confirm the endpoint is active in the correct test/live environment.
  2. Confirm its URL is public HTTPS and uses port 443 or 8443.
  3. Confirm the event type is selected.
  4. Check attempt history in the developer portal.
  5. Make sure your firewall accepts HaulStow’s request and your route accepts POST.
If signature verification fails:
  1. Confirm you used the webhook’s whsec_... secret, not an API key.
  2. Confirm the correct environment’s secret is loaded.
  3. Verify against the raw body before JSON parsing.
  4. Parse every v1 value during a rotation overlap.
  5. Make sure the server clock is accurate.