The Webhooks dashboard lives at wassist.app/developers/webhooks. Create one there, copy the signing secret, and you’re done.
How a delivery works
Behind the scenes:- The event is committed to our outbox as a
WebhookDeliverywith a stable UUID. - A worker POSTs the JSON body to your URL.
- We record an attempt row with status code, duration, and response body.
- On
5xxor network errors we retry up to 3 times with exponential backoff (10s, 30s, 90s). - After 20 consecutive failures the webhook is auto-disabled and you get a banner in the dashboard.
Headers
Verifying signatures
ComputeHMAC-SHA256 over the string <timestamp>.<raw body> using the webhook’s signing secret and compare it in constant time to the v1 component.
- Node.js
- Python
- Go
Event catalog
message.received
Fired when a customer sends a message to one of your numbers.
Ad attribution (Click-to-WhatsApp)
When the customer starts the chat by tapping a Click-to-WhatsApp ad (or a boosted post),message.referral carries the ad details WhatsApp attached to that message. latestReferral has the same shape and holds the most recent referral in the conversation. That means later messages in an ad-driven chat can still be attributed to the ad.
ctwaClid is the Click-to-WhatsApp click ID. Send it back to Meta via the Conversions API for Business Messaging to attribute leads and purchases to the ad. sourceId is the Meta ad (or post) ID. You can also look these up later: they’re on referral for each message returned by GET /conversations/{id}/messages/, and on latestReferral for each conversation. To filter conversations, use hasReferral, referralSourceId or ctwaClid. See Ad Attribution for the full field reference and a Conversions API example.
test.ping
Triggered by the dashboard Send test event button. Same envelope as a real event with a stub payload — use it to validate signature verification in CI.
Best practices
- Idempotency. Store the
X-Wassist-DeliveryID and reject duplicates. We use the same ID across all retries. - Respond fast. Send a
2xxwithin 10 seconds and do real work asynchronously. We treat slow responses as failures and retry. - Replay protection. Reject events where
X-Wassist-Timestampis more than 5 minutes from now. - Rotate secrets. From the dashboard, Rotate secret generates a new secret. The old one stops working immediately.
- Local development. Use the CLI:
wassist listentunnels real events tolocalhostwithout exposing a public URL.
Replaying deliveries
Every delivery is stored with its full payload. From the dashboard you can:- Filter deliveries by status (all / failed / succeeded).
- Open a delivery to see request headers, response body, and the timeline of every retry attempt.
- Click Replay to send a fresh copy of the same payload (it gets a new
X-Wassist-DeliveryID).
POST /api/v1/webhook-deliveries/{id}/replay/.