Webhooks
Receive signed delivery events on your HTTPS endpoint.
Register a webhook URL for your organisation. When a message reaches a terminal outcome, Netnaunse POSTs a JSON payload and signs the raw body with your endpoint secret.
Events
message.sent— message handed off successfullymessage.failed— delivery failed (customer-safe error code in payload)
Register an endpoint
curl -X POST https://api.netnaunse.com/v1/webhooks \
-H "Authorization: Bearer YOUR_TOKEN_OR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/netnaunse",
"events": ["message.sent", "message.failed"]
}'The create response includes a secret once. Store it securely — it is not returned again on list. You can also manage endpoints in the dashboard at app.netnaunse.com/webhooks.
List endpoints
curl https://api.netnaunse.com/v1/webhooks \
-H "Authorization: Bearer YOUR_TOKEN_OR_API_KEY"Delete an endpoint
curl -X DELETE https://api.netnaunse.com/v1/webhooks/ENDPOINT_ID \
-H "Authorization: Bearer YOUR_TOKEN_OR_API_KEY"Payload
{
"event": "message.sent",
"timestamp": "2026-09-03T10:43:16.000Z",
"data": {
"id": "cmexample123",
"to": "255712345678",
"status": "sent"
}
}{
"event": "message.failed",
"timestamp": "2026-09-03T10:43:16.000Z",
"data": {
"id": "cmexample123",
"to": "255712345678",
"errorCode": "MESSAGE_PROVIDER_ERROR"
}
}Headers
| Header | Description |
|---|---|
Content-Type | application/json |
X-Netnaunse-Event | Event name, e.g. message.sent |
X-Netnaunse-Signature | Hex HMAC-SHA256 of the raw request body using your endpoint secret |
Verify signatures
Compute HMAC-SHA256(secret, rawBody) and compare the hex digest to X-Netnaunse-Signature using a constant-time comparison. Reject requests that do not match.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, signatureHeader, secret) {
const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected, "utf8");
const b = Buffer.from(signatureHeader || "", "utf8");
return a.length === b.length && timingSafeEqual(a, b);
}Delivery semanticsDelivery is best-effort. Respond quickly with
2xx. Durable retry queues are on the roadmap — design your handler to be idempotent on data.id.