Webhooks API
Customer webhook endpoints and their delivery log. 11 ops: list_webhook_event_types, list_webhook_endpoints, create_webhook_endpoint, update_webhook_endpoint, delete_webhook_endpoint, rotate_webhook_secret, test_webhook_endpoint, list_webhook_deliveries, get_webhook_delivery, replay_webhook_delivery
Customer webhook endpoints and their delivery log.
List webhook event types · POST /api/v1/list_webhook_event_types · scope webhooks:read or GET …?input=
Every event a webhook endpoint can subscribe to with what it means, a sample delivery, the signature headers and the retry schedule.
curl -X POST https://getwabi.dev/api/v1/list_webhook_event_types \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi list_webhook_event_types{
"type": "object",
"properties": {}
}List webhook endpoints · POST /api/v1/list_webhook_endpoints · scope webhooks:read or GET …?input=
The organization's webhook endpoints with their event filters, status (active, failing, disabled) and health (consecutive failures, last success and failure, last error). Secrets are never returned.
curl -X POST https://getwabi.dev/api/v1/list_webhook_endpoints \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi list_webhook_endpoints{
"type": "object",
"properties": {}
}Create a webhook endpoint · POST /api/v1/create_webhook_endpoint · scope webhooks:write
Adds an HTTPS endpoint that receives signed platform events (all, or the event_types given). Returns the endpoint and its signing secret (whsec_…) once: store it to verify the webhook-signature header. Private and local addresses are refused.
curl -X POST https://getwabi.dev/api/v1/create_webhook_endpoint \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/webhooks/whatsapp"}'npx @meterapp/wabi create_webhook_endpoint --json '{"url":"https://example.com/webhooks/whatsapp"}'{
"type": "object",
"properties": {
"url": {
"type": "string",
"maxLength": 2000,
"format": "uri"
},
"description": {
"type": "string",
"maxLength": 500
},
"event_types": {
"default": [],
"maxItems": 16,
"type": "array",
"items": {
"type": "string",
"enum": [
"message.received",
"message.sent",
"message.delivered",
"message.read",
"message.failed",
"conversation.needs_reply",
"conversation.escalated",
"conversation.resolved",
"window.expiring",
"template.approved",
"template.rejected",
"template.quality_changed",
"flow.submitted",
"location.received",
"agent.session.completed",
"agent.execution.failed"
]
},
"description": "Event types to receive; empty: every event."
}
},
"required": [
"url"
]
}Update a webhook endpoint · POST /api/v1/update_webhook_endpoint · scope webhooks:write
Changes an endpoint's URL, description or event filter, or disables (enabled false: nothing is delivered) and re-enables it.
curl -X POST https://getwabi.dev/api/v1/update_webhook_endpoint \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/wabi update_webhook_endpoint --json '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Webhook endpoint id."
},
"url": {
"type": "string",
"maxLength": 2000,
"format": "uri"
},
"description": {
"type": "string",
"maxLength": 500
},
"event_types": {
"maxItems": 16,
"type": "array",
"items": {
"type": "string",
"enum": [
"message.received",
"message.sent",
"message.delivered",
"message.read",
"message.failed",
"conversation.needs_reply",
"conversation.escalated",
"conversation.resolved",
"window.expiring",
"template.approved",
"template.rejected",
"template.quality_changed",
"flow.submitted",
"location.received",
"agent.session.completed",
"agent.execution.failed"
]
},
"description": "Event types to receive; empty: every event."
},
"enabled": {
"type": "boolean"
}
},
"required": [
"endpoint"
]
}Delete a webhook endpoint · POST /api/v1/delete_webhook_endpoint · scope webhooks:write
Deletes an endpoint and its delivery log.
curl -X POST https://getwabi.dev/api/v1/delete_webhook_endpoint \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/wabi delete_webhook_endpoint --json '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Webhook endpoint id."
}
},
"required": [
"endpoint"
]
}Rotate a webhook secret · POST /api/v1/rotate_webhook_secret · scope webhooks:write
Issues a new signing secret, returned once. For grace_hours (default 24, 0: none) deliveries carry signatures from both the old and the new secret, so receivers can switch without dropping events.
curl -X POST https://getwabi.dev/api/v1/rotate_webhook_secret \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/wabi rotate_webhook_secret --json '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Webhook endpoint id."
},
"grace_hours": {
"default": 24,
"type": "integer",
"minimum": 0,
"maximum": 168
}
},
"required": [
"endpoint"
]
}Send a test webhook · POST /api/v1/test_webhook_endpoint · scope webhooks:write
Sends a signed webhook.test event to the endpoint now and returns its HTTP status, latency and the start of its answer. Not retried and not in the delivery log.
curl -X POST https://getwabi.dev/api/v1/test_webhook_endpoint \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/wabi test_webhook_endpoint --json '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Webhook endpoint id."
}
},
"required": [
"endpoint"
]
}List webhook deliveries · POST /api/v1/list_webhook_deliveries · scope webhooks:read or GET …?input=
The delivery log, newest first: each event sent to an endpoint with its status (pending, delivered, failed and retrying, dead), attempts, last HTTP status, latency, error and next retry. Filter by endpoint, status or event type.
curl -X POST https://getwabi.dev/api/v1/list_webhook_deliveries \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi list_webhook_deliveries{
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Webhook endpoint id."
},
"status": {
"type": "string",
"enum": [
"pending",
"delivered",
"failed",
"dead"
]
},
"event_type": {
"type": "string",
"enum": [
"message.received",
"message.sent",
"message.delivered",
"message.read",
"message.failed",
"conversation.needs_reply",
"conversation.escalated",
"conversation.resolved",
"window.expiring",
"template.approved",
"template.rejected",
"template.quality_changed",
"flow.submitted",
"location.received",
"agent.session.completed",
"agent.execution.failed"
]
},
"limit": {
"default": 50,
"description": "Page size, at most 200.",
"type": "integer",
"minimum": 1,
"maximum": 200
},
"offset": {
"default": 0,
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
}
}Get a webhook delivery · POST /api/v1/get_webhook_delivery · scope webhooks:read or GET …?input=
One delivery with every HTTP attempt (status, latency, the start of the answer, error) and the exact body that was signed.
curl -X POST https://getwabi.dev/api/v1/get_webhook_delivery \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"delivery":1}'npx @meterapp/wabi get_webhook_delivery --json '{"delivery":1}'{
"type": "object",
"properties": {
"delivery": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"delivery"
]
}Replay a webhook delivery · POST /api/v1/replay_webhook_delivery · scope webhooks:write
Sends one delivery again (a dead letter, or one you want re-processed) within a minute, with the same webhook-id. Returns the delivery.
curl -X POST https://getwabi.dev/api/v1/replay_webhook_delivery \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"delivery":1}'npx @meterapp/wabi replay_webhook_delivery --json '{"delivery":1}'{
"type": "object",
"properties": {
"delivery": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"delivery"
]
}Replay webhook events · POST /api/v1/replay_webhook_events · scope webhooks:write
Re-sends past events to an endpoint, from since (and until): with only_failed true (default) just its dead and failing deliveries; with false also events it never received (an endpoint added later, a filter widened). At most 1,000 events per call. Returns how many were reset and created.
curl -X POST https://getwabi.dev/api/v1/replay_webhook_events \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","since":"since"}'npx @meterapp/wabi replay_webhook_events --json '{"endpoint":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10","since":"since"}'{
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Webhook endpoint id."
},
"since": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
"until": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
},
"event_types": {
"type": "array",
"items": {
"type": "string",
"enum": [
"message.received",
"message.sent",
"message.delivered",
"message.read",
"message.failed",
"conversation.needs_reply",
"conversation.escalated",
"conversation.resolved",
"window.expiring",
"template.approved",
"template.rejected",
"template.quality_changed",
"flow.submitted",
"location.received",
"agent.session.completed",
"agent.execution.failed"
]
}
},
"only_failed": {
"default": true,
"type": "boolean"
}
},
"required": [
"endpoint",
"since"
]
}