Webhooks
Get a signed HTTP request the moment a message is delivered, fails or bounces.
Instead of polling, give us a URL and we POST an event to it whenever a message reaches a final outcome. Every event is signed, retried for up to 45 hours, and kept in an event log you can query and replay for 30 days.
Set up an endpoint
Expose a URL
Add a route to your server that accepts POST with a JSON body and returns any 2xx status. It must be:
https://, on the default port 443- reachable from the public internet (private and internal addresses are refused)
- able to respond within 10 seconds
Register it
curl -X PUT https://api.softlinksms.co.ke/api/v1/webhook-endpoint \
-H "X-Api-Key: $SOFTLINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/softlinksms",
"events": ["sms.delivered", "sms.failed"]
}'Leave out events to receive every event type. The first time you register, the response includes the endpoint's signing secret, shown only once:
{
"object": "webhook_endpoint",
"url": "https://example.com/webhooks/softlinksms",
"events": ["sms.delivered", "sms.failed"],
"secret_hint": "whsec_…Q2fA",
"secret": "whsec_hT9xV2...Q2fA",
"created_at": "2026-10-19T08:00:00Z",
"updated_at": "2026-10-19T08:00:00Z"
}Store it alongside your API key. Lost it? Rotate it.
Verify signatures
Every request carries a Softlink-Signature header. Check it before trusting the body; see Verify signatures for code in four languages.
Send a test event
curl -X POST https://api.softlinksms.co.ke/api/v1/webhook-endpoint/test \
-H "X-Api-Key: $SOFTLINK_API_KEY"You'll receive a signed webhook.test event within a few seconds. The response includes the event's id, so you can check how delivery went with GET /webhook-events/{id}.
What a request looks like
POST /webhooks/softlinksms HTTP/1.1
Host: example.com
Content-Type: application/json
User-Agent: SoftLinkSMS-Webhooks/1.0
Softlink-Event-Id: evt_6a1f0c2e9b8d4f3aa1c27e5d9b0f4e21
Softlink-Event-Type: sms.delivered
Softlink-Signature: t=1792396502,v1=5f2b0c0e7a9d...
{"id":"evt_6a1f0c2e9b8d4f3aa1c27e5d9b0f4e21","type":"sms.delivered","created_at":"2026-10-19T08:15:02Z","account_id":1042,"data":{"object":"sms","id":"3fae8b8e-9c3a-4e9a-9d3a-7e8e9c3a4e9a","recipient":"+254712345678","status":"delivered",...}}See Events for every event type and its payload.
Best practices
Managing the endpoint
| Task | Request |
|---|---|
| See the current endpoint | GET /webhook-endpoint |
| Change the URL or events | PUT /webhook-endpoint (the secret stays the same) |
| Rotate the signing secret | POST /webhook-endpoint/rotate-secret |
| Stop all events | DELETE /webhook-endpoint |
Changing the endpoint needs the webhooks:write scope; reading it and the event log needs webhooks:read. You can also set the URL in the dashboard under Settings → Notifications.