Skip to Content

Webhooks

Verify and parse the sms.delivered/sms.failed events. The signature is the HMAC-SHA256 hex digest of the raw body in the X-SendAfrica-Signature header — verify before parsing JSON.

import crypto from 'node:crypto' import { NextResponse } from 'next/server' export async function POST(request: Request) { const rawBody = await request.text() const expected = crypto .createHmac('sha256', process.env.SENDAFRICA_WEBHOOK_SECRET!) .update(rawBody) .digest('hex') const actual = request.headers.get('x-sendafrica-signature') ?? '' if ( actual.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(actual)) ) { return NextResponse.json({ error: 'invalid signature' }, { status: 401 }) } const event = JSON.parse(rawBody) console.log(event.event, event.message_id, event.to, event.status) return NextResponse.json({ ok: true }) // durable work before this return }

Correct response semantics

  • Return 2xx only after the event is durably processed — persist or queue before the 200.
  • Ack fast, process heavy work asynchronously.
  • Deduplicate on (message_id, event) — retries can deliver duplicates.

See Webhooks for the full contract, retry backoff, and endpoint-management API.

Last updated on