API keys & webhooks
Scoped API keys authenticate REST calls. Webhooks push the same events to your systems with HMAC-SHA256 signatures and automatic retries.
API key shape
Keys are created in Settings → Developer (OWNER or ADMIN only). The plaintext is shown exactly once at creation — WhautX stores only the SHA-256 hash and a 25-character display prefix.
whautx_live_ + 48 hex chars (~192 bits entropy)Send it as Authorization: Bearer whautx_live_xxx. Revoked and expired keys fail at lookup time.
Scopes
Each endpoint requires at least one scope. A request to an endpoint whose scope your key lacks returns 403 Forbidden.
contacts.readGET /contacts, /contacts/:id, /conversations, conversation messages.contacts.writePOST /contacts, PATCH /contacts/:id.messages.sendPOST /messages (text inside the 24-hour window).campaigns.readGET /campaigns.campaigns.writePOST /campaigns — drafts only; start them from the app.forms.submitPOST /forms/:formId/submit (server-to-server form ingestion).knowledge.readGET /knowledge (metadata only — never raw embeddings).
Webhooks
Webhook subscriptions are independent of API keys. Register a URL and pick the events you want delivered. Each subscription gets its own signing secret — never reuse one across endpoints.
Event catalog
message.receivedInbound WhatsApp message from a contact.message.deliveredOutbound message delivered (mirrored from Meta).message.readOutbound message read by the recipient.contact.createdA new contact was added to your workspace.deal.stage_changedA deal moved between pipeline stages.campaign.completedA campaign finished sending.
Payload shape
Every delivery is a versioned envelope — data varies by event, but event and deliveredAt are always present.
{
"event": "message.received",
"deliveredAt": "2026-07-18T12:34:56.789Z",
"data": { /* event-specific */ }
}Signature verification
Every delivery carries an X-WhautX-Signature: sha256=<hex> header. Compute it as HMAC-SHA256 of the raw body using the subscription secret, and compare with a constant-time equality check.
import crypto from "node:crypto";
export function verify(rawBody, signatureHeader, secret) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Retry policy
- Up to 3 attempts per delivery.
- Exponential backoff: 30s, 60s, 120s.
- Per-request timeout: 8 seconds.
- Every attempt — including the final failure — is logged on a
WebhookDeliveryrow you can inspect via the Developer page.