Webhooks
Register HTTPS endpoints to receive events. Manage them with POST/GET /v1/webhooks,
PATCH/DELETE /v1/webhooks/{id}, inspect GET /v1/webhooks/{id}/deliveries, and re-fire
with POST /v1/webhooks/{id}/deliveries/{delivery_id}/replay.
Payload & signature​
Each delivery is POSTed as JSON { "event", "timestamp", "data" } with headers:
| Header | Meaning |
|---|---|
X-Wapower-Event | the event type |
X-Wapower-Delivery-Id | unique per delivery — dedupe on this (at-least-once) |
X-Wapower-Signature | HMAC-SHA256 of the exact request body, keyed by your endpoint secret |
Verify the signature by recomputing HMAC-SHA256 over the raw body with your secret and
comparing in constant time. Failed deliveries retry with backoff until max_attempts.
Events​
Outbound / protection (existing): message.sent, message.blocked_by_protection,
session.status, session.banned, session.warmup.disabled, warmup.stage.advanced,
protection.state.changed, session.risk.alert.
Inbound / real-time: message.received, message.delivered, message.read,
message.reaction, call.received, session.qr, group.participants.update, group.update.
session.status also fires on spontaneous connection changes detected by the engine
(disconnect/ban/reconnect), not only on API calls.
Subscribe to specific types or *.
Inbound payloads​
message.received—data:session_id, message_id, from, push_name, type, from_me, is_group, timestampplustext?,media?{url,mime,size,sha256,file_name?,caption?},location?,contact?,quoted_message_id?. Incoming media is re-hosted;media.urlis a time-limited link. If a media download failed,mediais{ "error": "download_failed" }.message.delivered/message.read—data:session_id, message_id, internal_id, to, timestamp.internal_idis the id returned when you sent the message via the API (nullif it wasn't sent through us).message.reaction—data:session_id, message_id, from, emoji, timestamp(emoji: ""means the reaction was removed).call.received—data:session_id, call_id, from, is_video, status:"offer", timestamp.session.qr—data:session_id, qr, timestamp.group.participants.update—data:session_id, group_id, participants:[jid], action:"add"|"remove"|"promote"|"demote", timestamp.group.update—data:session_id, group_id, changes:{subject?,description?}, timestamp.message.receivedfor a group message additionally hasis_group:trueandgroup_id;fromis the participant who sent it (not the group jid).