message.sent, message.delivered, message.read, message.failed.message.received.message.bounced, message.unsubscribed, message.opened, message.clicked.campaign.completed, contact.created, form.submitted.data. Treat timestamps and provider IDs as useful context, and inspect the fields for the actual event you subscribe to rather than assuming all event types share one schema.1234567891011{ "event": "message.delivered", "created_at": "2026-10-11T09:00:00Z", "data": { "message_id": 8841, "to": "+2348012345678", "channel": "whatsapp", "status": "delivered", "provider_message_id": "wamid.example" } }
X-Convert-Signature: sha256=<hex>. Verify before processing; JSON parsing and reserialization changes the signed bytes.123456789101112import crypto from "node:crypto"; export function verifyConvertSignature(rawBody, signature, secret) { if (!Buffer.isBuffer(rawBody) || typeof signature !== "string") return false; const expected = Buffer.from( "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex"), "utf8" ); const supplied = Buffer.from(signature, "utf8"); return supplied.length === expected.length && crypto.timingSafeEqual(supplied, expected); }
timingSafeEqual throw. Store the secret server-side and keep it separate from your Bearer API key.2xx response after safely accepting the event. Queue expensive application processing so the receiver responds promptly. Connection failures, timeouts, and non-2xx responses are retried with backoff up to five attempts.