API reference
Debugging webhooks
Using the deliveries log, replaying failed deliveries, the test-fire endpoint, and the auto-pause threshold.
Last updated
Webhooks fail in mysterious ways. Here's the debugging path that catches 95% of issues.
Test fire
Hit POST /api/v1/webhooks/{id}/test (or jobbydev_webhook_test from your agent) to send a synthetic event with a known payload to your endpoint. Useful when:
- First wiring up signature verification.
- Confirming the endpoint accepts POSTs at all.
- Debugging without waiting for a real match to fire.
The deliveries log
GET /api/v1/webhooks/{id}/deliveries returns the 50 most recent delivery attempts with:
- Event type and event ID.
- Attempted-at timestamp.
- HTTP status returned by your endpoint (or null on timeout).
- Response body (first 1024 bytes).
- Next-retry timestamp (null once delivered or dead-lettered).
- Final state: delivered, retrying, dead-lettered.
Browser UI at /account/webhooks renders this same data with filters by status and event type.
Common failure shapes
Signature verification fails on every delivery
Almost always one of:
- You're computing HMAC over the parsed-then-stringified body, not the raw bytes. Frameworks like Express auto-parse JSON; you need to opt into raw body for the webhook route.
- You stored the wrong secret. We only show the secret once on subscription creation. If you lost it, rotate the secret in the dashboard and update your endpoint.
- You're comparing strings with
==instead of a constant-time function. Most stdlib HMAC modules expose one.
Endpoint times out
Your handler has 10 seconds. If you're doing real work (parsing, DB writes, fan-out to other services) inline, you'll hit the cap on busy events. The fix is to accept-and-queue:
- Verify signature.
- Push event to a local queue (Redis, SQS, in-memory channel).
- Return 200 immediately.
- Process the queue async with whatever timeout you want.
Subscription auto-paused
After 25 consecutive failures across all events, the subscription is paused — the trip-wire prevents your endpoint from soaking delivery worker bandwidth indefinitely. You get an email notification. Steps to recover:
- Pull the deliveries log; identify the systematic failure (502 Bad Gateway, signature error, timeout).
- Fix the underlying issue.
- Test-fire to confirm a delivery succeeds.
- Re-enable the subscription via PATCH or the dashboard.
Duplicate events
Inevitable under at-least-once delivery. We retry on timeout or non-2xx response, and your endpoint may have actually processed the event before timing out. Use the event id field as your idempotency key — store processed IDs for at least 24 hours and skip duplicates.
Out-of-order events
Less common, but possible. We retry failed deliveries on a back-off schedule that can interleave with newer events for the same subscription. Use the created_attimestamp on the payload to detect and either reorder or discard stale events. Don't rely on delivery order.
Replaying a delivery
Today: not directly. Workarounds:
- Use
POST /api/v1/webhooks/{id}/testto fire a synthetic event with the same shape. - Use the deliveries log to find the original payload and POST it to your endpoint manually (re-sign with your secret).
Direct replay-from-log is on the Tier 7 follow-up backlog.
Local development
For local-machine endpoints, use a tunneling tool (ngrok, cloudflared, localtunnel) to expose your dev server. Subscribe with the tunnel URL as the target_url; tear down and rotate when done.