Reference
Webhooks
Pulsr pushes what happens after a request (delivery reports, inbound messages, call events) to an HTTPS endpoint on your side, as a POST with a JSON body.
What you can receive
| Event | Where to set the URL | Guide |
|---|---|---|
| SMS delivery reports | webhooks.delivery.url on each send | Delivery reports |
| Inbound SMS | On your number, in the dashboard | Receive SMS |
| RCS delivery and seen reports | webhooks.delivery.url and webhooks.seen.url on each send | RCS |
| Inbound RCS and button taps | On your RCS sender, in the dashboard | RCS |
| Call events | An event subscription on your calls configuration | Voice |
Write a handler
Message webhooks carry a results array, so one request can hold several events; call events arrive one per request. A good handler checks that the request comes from Pulsr, stores or queues the events, and answers 200 straight away.
app/webhooks/pulsr/route.ts
Secure your endpoint
- Use HTTPS. Webhook URLs must be publicly reachable over HTTPS with a valid certificate.
- Add a secret to the URL. Generate a long random value, add it as a query parameter (
https://yourapp.com/webhooks/pulsr?token=…) and compare it in constant time, as in the handler above. Rotate it like any other secret. - Never trust the payload blindly. Look the
messageIdup in your own records before acting on an event.
Acknowledge and deduplicate
- Answer fast. Return a
2xxstatus as soon as the events are safely stored. Do slow work (database updates, emails, your own API calls) in a background job. - Expect duplicates. If your endpoint times out or fails, the same event can be sent again. Make processing idempotent by keying on
messageId(orcallIdfor voice) and the status. - Do not rely on order. Events can arrive out of order. Compare timestamps such as
doneAtbefore overwriting a newer status with an older one.
Test locally
Pulsr needs a public URL to reach your laptop. Run a tunnel such as ngrok http 3000 or cloudflared tunnel --url http://localhost:3000, then use the HTTPS address it prints as your webhook URL.