Set the webhook endpoint
Points WASync at your URL and returns the signing secret for it. Idempotent — calling it again with a different URL moves the endpoint. The URL must be HTTPS on a publicly reachable host; http, localhost and private ranges are rejected with 400 `invalid_webhook`. Signature scheme (unchanged): every delivery carries `X-WASync-Signature: sha256=<hex>` = HMAC-SHA256 of `${X-WASync-Timestamp}.${rawBody}` keyed with this secret. `X-WASync-Timestamp` is epoch milliseconds; reject anything older than 5 minutes. Verify over the RAW body, before parsing. Full contract: https://developers.wasync.app/docs/webhooks
Points WASync at your URL and returns the signing secret for it. Idempotent — calling it again with a different URL moves the endpoint.
The URL must be HTTPS on a publicly reachable host; http, localhost and private ranges are rejected with 400 invalid_webhook.
Signature scheme (unchanged): every delivery carries X-WASync-Signature: sha256=<hex> = HMAC-SHA256 of ${X-WASync-Timestamp}.${rawBody} keyed with this secret. X-WASync-Timestamp is epoch milliseconds; reject anything older than 5 minutes. Verify over the RAW body, before parsing. Full contract: https://developers.wasync.app/docs/webhooks
The default way to authenticate. Create a key at https://developers.wasync.app/keys and send it as Authorization: Bearer wsk_live_….
The key is shown once at creation and stored only as a hash — lose it and you revoke it and create another. Each key carries its own scopes (whatsapp.read, whatsapp.send, whatsapp.events, whatsapp.manage) and an optional IP allowlist.
Errors: an unknown or revoked key returns 401 invalid_key; a key whose IP allowlist does not cover the calling address returns 403 ip_not_allowed (a distinct code on purpose — the key is fine, the address is not). Both carry a WWW-Authenticate: Bearer challenge. Scopes and the connection list are resolved live on every request, so revoking a key or narrowing it takes effect on the next call.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X PUT "https://example.com/webhook" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/wasync/webhook" }'{ "url": "https://example.com/wasync/webhook", "events": [ "message.received", "message.status", "connection.disconnected", "connection.connected" ], "secret": "whsec_3f9a…"}Read the webhook configuration GET
Returns the endpoint URL, the event types delivered to it, and whether a signing secret is set. **The secret is never returned here.** A read is routinely logged, cached and pasted into support tickets; a secret that leaks through it is a secret you cannot reason about. If you lost yours, rotate it — which is what you would have to do after a leak anyway.
Rotate the webhook signing secret POST
Issues a new signing secret and invalidates the old one immediately — there is no overlap window. Deploy the new secret to your receiver promptly; the retry policy (3 attempts with exponential backoff) covers a rollout measured in seconds, not hours. Signature scheme (unchanged): every delivery carries `X-WASync-Signature: sha256=<hex>` = HMAC-SHA256 of `${X-WASync-Timestamp}.${rawBody}` keyed with this secret. `X-WASync-Timestamp` is epoch milliseconds; reject anything older than 5 minutes. Verify over the RAW body, before parsing. Full contract: https://developers.wasync.app/docs/webhooks