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 successfully
  • message.failed — delivery failed (customer-safe error code in payload)

Register an endpoint

POST /v1/webhooks
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

GET /v1/webhooks
curl https://api.netnaunse.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_TOKEN_OR_API_KEY"

Delete an endpoint

DELETE /v1/webhooks/{id}
curl -X DELETE https://api.netnaunse.com/v1/webhooks/ENDPOINT_ID \
  -H "Authorization: Bearer YOUR_TOKEN_OR_API_KEY"

Payload

message.sent
{
  "event": "message.sent",
  "timestamp": "2026-09-03T10:43:16.000Z",
  "data": {
    "id": "cmexample123",
    "to": "255712345678",
    "status": "sent"
  }
}
message.failed
{
  "event": "message.failed",
  "timestamp": "2026-09-03T10:43:16.000Z",
  "data": {
    "id": "cmexample123",
    "to": "255712345678",
    "errorCode": "MESSAGE_PROVIDER_ERROR"
  }
}

Headers

HeaderDescription
Content-Typeapplication/json
X-Netnaunse-EventEvent name, e.g. message.sent
X-Netnaunse-SignatureHex 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.

Node.js verification sketch
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.

Related: SMS API · Errors