Documentation menu

Delivery reports

Register a webhook and we post every delivery event the moment a network confirms it. No polling.

Register a webhook

curl
curl https://api.sms.pesarails.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/hooks/sms",
    "events": ["message.delivered", "message.undelivered"]
  }'

The response includes a signing secret, shown once. Store it to verify incoming events.

Events

EventWhen
message.sentHanded to the network.
message.deliveredConfirmed on the handset.
message.undeliveredThe network could not deliver it.
message.failedRejected before sending. Credit refunded.

Leave events empty to receive all of them.

The payload

We POST JSON to your URL with the event, the message data, and a timestamp.

POST https://your-app.com/hooks/sms
{
  "event": "message.delivered",
  "data": {
    "messageId": "a1b2c3",
    "to": "254712345678",
    "description": "DeliveredToTerminal"
  },
  "timestamp": "2026-10-29T10:16:10.000Z"
}

Verify the signature

Every request carries an x-rsms-signature header: an HMAC-SHA256 of the raw body, keyed with your webhook secret. Verify it before trusting the payload.

verify.ts
import crypto from "node:crypto";

function verify(rawBody: string, signature: string, secret: string) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
Tip

Respond 200 quickly and do your work afterwards. We retry on non-2xx responses, so make your handler idempotent.