Device webhooks — configure, rotate, delete
/devices/{id}/webhook
Section titled “/devices/{id}/webhook”Manages where a rented number’s WhatsApp events are delivered. All four methods need the webhook scope and
an active/past_due rental for the device.
GET — read the current destination
Section titled “GET — read the current destination”{ "ok": true, "webhook": { "id": "rwh_…", "deviceId": "gwd_…", "url": "https://…", "events": ["message"], "active": true, "createdAt": "…", "updatedAt": "…" }, "availableEvents": ["message", "message.reaction", "message.revoked", "message.edited", "message.ack", "message.deleted", "chat_presence", "group.participants", "group.joined", "label.edit", "label.association", "newsletter.joined", "newsletter.left", "newsletter.message", "newsletter.mute", "call.offer"], "gatewayWired": true}webhook is null when nothing is configured. gatewayWired reports whether the gateway has been
confirmed wired to MauKirim — if it is false, events are not flowing yet and that is not your endpoint’s
fault. The signing secret is never returned by a read.
The destination belongs to the current lease, not just the current account. A number rented again —
even by the same account — does not carry the previous destination into its settings: a read returns null,
and the first POST deletes the previous destination and its deliveries, then issues a fresh signing secret.
For per-chat typing events on a rented number, subscribe to chat_presence alongside any other events
you want. See the chat presence webhook example
for the signed delivery envelope. To show typing from your rented number, use
POST /devices/{id}/chat-presence.
POST — create or edit
Section titled “POST — create or edit”| Field | Type | Required | Validation |
|---|---|---|---|
url |
string | yes | Parseable, https, no userinfo, no query, no fragment, not an IP literal and not localhost/*.localhost/*.local |
events |
string[] | no | Defaults to [], which means all events. Duplicates are removed; unknown names are rejected. |
active |
boolean | no | Defaults to true on create; on an edit the existing value is kept unless you send one |
{ "ok": true, "webhook": { "…": "…" }, "secret": "…64 hex characters…" }secret appears only when the destination was newly created. Editing an existing destination keeps the
secret and returns no secret field — which is why storing the value the first time matters.
PUT — rotate the signing secret
Section titled “PUT — rotate the signing secret”No body. Returns the same shape with a new secret. The previous secret stops verifying immediately, so
deploy the new one before rotating unless you can tolerate a failed delivery.
404 webhook_not_configured when there is nothing to rotate.
DELETE — remove the destination
Section titled “DELETE — remove the destination”{ "ok": true, "removed": true }Events stop being forwarded and the destination is removed. The device and its rental are untouched, but the
delivery log goes with the destination — its rows are deleted alongside it, so export anything you still
need first. 404 webhook_not_configured when nothing was configured.
Errors for all four
Section titled “Errors for all four”| HTTP | Code | Condition |
|---|---|---|
| 400 | invalid_input |
url missing, unparseable, not https, carrying credentials/query/fragment, an IP literal or localhost; events not a list of known names |
| 404 | rental_not_found |
No usable rental for this device and account |
| 404 | webhook_not_configured |
PUT/DELETE with no destination |
| 401/403 | auth codes | Needs scope webhook |
| 500 | server_error |
Unexpected |