Webhooks
Get events (new messages, delivery updates) pushed to your server.
Endpoints
- getList event types
/event_types - postRetry a delivery now
/webhook_deliveries/{id}/retry - getList webhook endpoints
/webhook_endpoints - postAdd a webhook endpoint
/webhook_endpoints - getGet a webhook endpoint
/webhook_endpoints/{id} - patchUpdate a webhook endpoint
/webhook_endpoints/{id} - DELDelete a webhook endpoint
/webhook_endpoints/{id} - getList deliveries
/webhook_endpoints/{id}/deliveries - postRotate the signing secret
/webhook_endpoints/{id}/rotate_secret - postSend a test event
/webhook_endpoints/{id}/test
List event types
https://api.saei.automize.sa/v1/event_types- Scope:
webhooks:read - Works in test mode
Every event you can subscribe an endpoint to.
Response fields200· The event types.
object"list"requireddataarray<EventType>requiredChild fields (4)
object"event_type"requiredtypestringrequiredobject_typestringoptionaldescriptionstringrequired
has_morebooleanrequirednext_cursorstring | nullrequired
Try it
curl -X GET https://api.saei.automize.sa/v1/event_types \
-H "Authorization: Bearer $API_KEY"The event types.
{
"object": "list",
"data": [
{
"object": "event_type",
"type": "message.delivered",
"object_type": "string",
"description": "string"
}
],
"has_more": false,
"next_cursor": "string"
}Retry a delivery now
https://api.saei.automize.sa/v1/webhook_deliveries/{id}/retry- Scope:
webhooks:write - Works in test mode
Sends the same event again (same webhook-id, fresh signature), e.g. after you fixed your server.
Path parameters
idstringrequiredThe object's id.
Response fields202· Queued.
idstringrequiredobject"webhook_delivery"requiredlivemodebooleanrequiredwebhook_endpoint_idstringrequiredevent_idstringrequiredevent_typestringrequiredstatusstringrequiredfailedwill be retried atnext_attempt_at;deadwill not be retried again.One of
pendingsucceededfaileddeadattemptsintegerrequiredhttp_statusinteger | nulloptionalduration_msinteger | nulloptionalresponse_snippetstring | nulloptionallast_errorstring | nulloptionalnext_attempt_atstring | nulloptionaldelivered_atstring | nulloptionalcreated_atstring | nulloptionalpayloadobjectoptionalThe body of every webhook request.
data.objectis exactly the resource the REST API returns (e.g. amessage).Child fields (8)
idstringrequiredEvent id, also sent as the
webhook-idheader. The same on every retry, so use it to ignore duplicates.object"event"requiredtypestringrequiredversionstringrequiredPayload version. Fields are only ever added within a version.
created_atstringrequiredlivemodebooleanrequiredworkspace_idstringrequireddataobjectrequiredChild fields (2)
objectobjectrequiredprevious_attributesobjectoptionalThe values that changed, as they were before, when known.
Errors this can return1
- 404resource_missingNot found
Try it
curl -X POST https://api.saei.automize.sa/v1/webhook_deliveries/del_01j9x3k2m4n5p6q7r8s9t0v1w2/retry \
-H "Authorization: Bearer $API_KEY"Queued.
{
"id": "del_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_delivery",
"livemode": false,
"webhook_endpoint_id": "string",
"event_id": "string",
"event_type": "string",
"status": "pending",
"attempts": 0,
"http_status": 0,
"duration_ms": 0,
"response_snippet": "string",
"last_error": "string",
"next_attempt_at": "2026-10-01T09:30:00Z",
"delivered_at": "2026-10-01T09:30:00Z",
"created_at": "2026-10-01T09:30:00Z",
"payload": {
"id": "evt_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "event",
"type": "message.delivered",
"version": "2",
"created_at": "2026-10-01T09:30:00Z",
"livemode": false,
"workspace_id": "ws_12",
"data": {
"object": {},
"previous_attributes": {}
}
}
}List webhook endpoints
https://api.saei.automize.sa/v1/webhook_endpoints- Scope:
webhooks:read - Works in test mode
The endpoints in the key's mode (live keys see live endpoints, test keys test endpoints).
Response fields200· The endpoints.
object"list"requireddataarray<WebhookEndpoint>requiredChild fields (12)
idstringrequiredobject"webhook_endpoint"requiredlivemodebooleanrequiredLive endpoints get live events; test endpoints get test-mode events. Never both.
urlstringrequireddescriptionstring | nulloptionalenabled_eventsarray<string>requiredEvent types to send, a whole group such as
contact.*, or["*"]for all.statusstringrequiredauto_disabledafter 3 days of failed deliveries or a410 Goneanswer.One of
enableddisabledauto_disableddisabled_reasonstring | nulloptionalsecret_previewstringoptionalsecretstringoptionalThe signing secret (
whsec_…). Returned only when the endpoint is created or its secret rotated. Store it now.created_atstring | nullrequiredupdated_atstring | nulloptional
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return1
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/webhook_endpoints \
-H "Authorization: Bearer $API_KEY"The endpoints.
{
"object": "list",
"data": [
{
"id": "we_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_endpoint",
"livemode": false,
"url": "string",
"description": "string",
"enabled_events": [
"string"
],
"status": "enabled",
"disabled_reason": "string",
"secret_preview": "string",
"secret": "string",
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}
],
"has_more": false,
"next_cursor": "string"
}Add a webhook endpoint
https://api.saei.automize.sa/v1/webhook_endpoints- Scope:
webhooks:write - Works in test mode
- Accepts Idempotency-Key
We will POST each subscribed event to url as JSON, signed with the Standard Webhooks scheme. The response includes the signing secret once: store it to verify signatures.
In production the URL must be https:// and publicly reachable. Up to 10 endpoints per workspace.
An event carries the same data its read endpoint returns, so each event family needs that read scope: message.* needs messages:read, contact.* contacts:read, conversation.* conversations:read, campaign.* campaigns:read, flow.* flows:read, template.* templates:read. ["*"] needs all of them. The same check applies when you change the URL or events of an endpoint.
Headers
Idempotency-KeystringoptionalAny unique string (a UUID is ideal). Retrying with the same key and body returns the first response instead of acting twice. Remembered for 24 hours.
Request body
urlstringrequiredWhere to send events.
enabled_eventsarray<string>requiredEvent types from
GET /v1/event_types, a whole group such ascontact.*, or["*"]for all.descriptionstringoptional
Response fields201· Created. `secret` is shown only now.
idstringrequiredobject"webhook_endpoint"requiredlivemodebooleanrequiredLive endpoints get live events; test endpoints get test-mode events. Never both.
urlstringrequireddescriptionstring | nulloptionalenabled_eventsarray<string>requiredEvent types to send, a whole group such as
contact.*, or["*"]for all.statusstringrequiredauto_disabledafter 3 days of failed deliveries or a410 Goneanswer.One of
enableddisabledauto_disableddisabled_reasonstring | nulloptionalsecret_previewstringoptionalsecretstringoptionalThe signing secret (
whsec_…). Returned only when the endpoint is created or its secret rotated. Store it now.created_atstring | nullrequiredupdated_atstring | nulloptional
Errors this can return6
- 403insufficient_scopeMissing permission
- 422parameter_missingMissing parameter
- 422parameter_invalidInvalid parameter
- 422webhook_url_invalidWebhook URL not allowed
- 422webhook_endpoint_limitToo many endpoints
- 429rate_limitedToo many requests
Try it
curl -X POST https://api.saei.automize.sa/v1/webhook_endpoints \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/whatsapp",
"enabled_events": [
"message.received",
"message.delivered",
"message.read",
"message.failed"
],
"description": "Order system"
}'Created. `secret` is shown only now.
{
"id": "we_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_endpoint",
"livemode": true,
"url": "https://example.com/webhooks/whatsapp",
"description": "Order system",
"enabled_events": [
"message.received",
"message.delivered",
"message.read",
"message.failed"
],
"status": "enabled",
"disabled_reason": null,
"secret_preview": "whsec_…K3x=",
"secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw/kNEBw0UXK3x=",
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Get a webhook endpoint
https://api.saei.automize.sa/v1/webhook_endpoints/{id}- Scope:
webhooks:read - Works in test mode
Path parameters
idstringrequiredThe object's id.
Response fields200· The endpoint.
idstringrequiredobject"webhook_endpoint"requiredlivemodebooleanrequiredLive endpoints get live events; test endpoints get test-mode events. Never both.
urlstringrequireddescriptionstring | nulloptionalenabled_eventsarray<string>requiredEvent types to send, a whole group such as
contact.*, or["*"]for all.statusstringrequiredauto_disabledafter 3 days of failed deliveries or a410 Goneanswer.One of
enableddisabledauto_disableddisabled_reasonstring | nulloptionalsecret_previewstringoptionalsecretstringoptionalThe signing secret (
whsec_…). Returned only when the endpoint is created or its secret rotated. Store it now.created_atstring | nullrequiredupdated_atstring | nulloptional
Errors this can return1
- 404resource_missingNot found
Try it
curl -X GET https://api.saei.automize.sa/v1/webhook_endpoints/we_01j9x3k2m4n5p6q7r8s9t0v1w2 \
-H "Authorization: Bearer $API_KEY"The endpoint.
{
"id": "we_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_endpoint",
"livemode": false,
"url": "string",
"description": "string",
"enabled_events": [
"string"
],
"status": "enabled",
"disabled_reason": "string",
"secret_preview": "string",
"secret": "string",
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Update a webhook endpoint
https://api.saei.automize.sa/v1/webhook_endpoints/{id}- Scope:
webhooks:write - Works in test mode
Change the URL or events, or pause it with "disabled": true. Re-enabling clears the failure count.
Path parameters
idstringrequiredThe object's id.
Request body
urlstringoptionalenabled_eventsarray<string>optionaldescriptionstring | nulloptionaldisabledbooleanoptional
Response fields200· The updated endpoint.
idstringrequiredobject"webhook_endpoint"requiredlivemodebooleanrequiredLive endpoints get live events; test endpoints get test-mode events. Never both.
urlstringrequireddescriptionstring | nulloptionalenabled_eventsarray<string>requiredEvent types to send, a whole group such as
contact.*, or["*"]for all.statusstringrequiredauto_disabledafter 3 days of failed deliveries or a410 Goneanswer.One of
enableddisabledauto_disableddisabled_reasonstring | nulloptionalsecret_previewstringoptionalsecretstringoptionalThe signing secret (
whsec_…). Returned only when the endpoint is created or its secret rotated. Store it now.created_atstring | nullrequiredupdated_atstring | nulloptional
Errors this can return4
- 403insufficient_scopeMissing permission
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 422webhook_url_invalidWebhook URL not allowed
Try it
curl -X PATCH https://api.saei.automize.sa/v1/webhook_endpoints/we_01j9x3k2m4n5p6q7r8s9t0v1w2 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled_events": [
"*"
]
}'The updated endpoint.
{
"id": "we_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_endpoint",
"livemode": false,
"url": "string",
"description": "string",
"enabled_events": [
"string"
],
"status": "enabled",
"disabled_reason": "string",
"secret_preview": "string",
"secret": "string",
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Delete a webhook endpoint
https://api.saei.automize.sa/v1/webhook_endpoints/{id}- Scope:
webhooks:write - Works in test mode
Stops all deliveries to it, including pending retries.
Path parameters
idstringrequiredThe object's id.
Response fields200· Deleted.
idstringrequiredobject"webhook_endpoint"requireddeletedtruerequired
Errors this can return1
- 404resource_missingNot found
Try it
curl -X DELETE https://api.saei.automize.sa/v1/webhook_endpoints/we_01j9x3k2m4n5p6q7r8s9t0v1w2 \
-H "Authorization: Bearer $API_KEY"Deleted.
{
"id": "string",
"object": "webhook_endpoint",
"deleted": true
}List deliveries
https://api.saei.automize.sa/v1/webhook_endpoints/{id}/deliveries- Scope:
webhooks:read - Works in test mode
Every attempt to deliver an event to this endpoint, newest first, with the HTTP status your server answered.
Path parameters
idstringrequiredThe object's id.
Query parameters
limitintegeroptionalHow many objects to return, 1 to 100.
cursorstringoptionalThe
next_cursorfrom the previous page.statusstringoptionalOnly deliveries in this state.
One of
pendingsucceededfaileddead
Response fields200· A page of deliveries.
object"list"requireddataarray<WebhookDelivery>requiredChild fields (16)
idstringrequiredobject"webhook_delivery"requiredlivemodebooleanrequiredwebhook_endpoint_idstringrequiredevent_idstringrequiredevent_typestringrequiredstatusstringrequiredfailedwill be retried atnext_attempt_at;deadwill not be retried again.One of
pendingsucceededfaileddeadattemptsintegerrequiredhttp_statusinteger | nulloptionalduration_msinteger | nulloptionalresponse_snippetstring | nulloptionallast_errorstring | nulloptionalnext_attempt_atstring | nulloptionaldelivered_atstring | nulloptionalcreated_atstring | nulloptionalpayloadobjectoptionalThe body of every webhook request.
data.objectis exactly the resource the REST API returns (e.g. amessage).Child fields (8)
idstringrequiredEvent id, also sent as the
webhook-idheader. The same on every retry, so use it to ignore duplicates.object"event"requiredtypestringrequiredversionstringrequiredPayload version. Fields are only ever added within a version.
created_atstringrequiredlivemodebooleanrequiredworkspace_idstringrequireddataobjectrequiredChild fields (2)
objectobjectrequiredprevious_attributesobjectoptionalThe values that changed, as they were before, when known.
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return1
- 404resource_missingNot found
Try it
curl -X GET https://api.saei.automize.sa/v1/webhook_endpoints/we_01j9x3k2m4n5p6q7r8s9t0v1w2/deliveries \
-H "Authorization: Bearer $API_KEY"A page of deliveries.
{
"object": "list",
"data": [
{
"id": "del_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_delivery",
"livemode": false,
"webhook_endpoint_id": "string",
"event_id": "string",
"event_type": "string",
"status": "pending",
"attempts": 0,
"http_status": 0,
"duration_ms": 0,
"response_snippet": "string",
"last_error": "string",
"next_attempt_at": "2026-10-01T09:30:00Z",
"delivered_at": "2026-10-01T09:30:00Z",
"created_at": "2026-10-01T09:30:00Z",
"payload": {
"id": "evt_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "event",
"type": "message.delivered",
"version": "2",
"created_at": "2026-10-01T09:30:00Z",
"livemode": false,
"workspace_id": "ws_12",
"data": {
"object": {},
"previous_attributes": {}
}
}
}
],
"has_more": false,
"next_cursor": "string"
}Rotate the signing secret
https://api.saei.automize.sa/v1/webhook_endpoints/{id}/rotate_secret- Scope:
webhooks:write - Works in test mode
Returns a new secret. For 24 hours every event is signed with both the old and the new secret, so you can deploy the new one without missing events.
Path parameters
idstringrequiredThe object's id.
Response fields200· The endpoint, with its new secret.
idstringrequiredobject"webhook_endpoint"requiredlivemodebooleanrequiredLive endpoints get live events; test endpoints get test-mode events. Never both.
urlstringrequireddescriptionstring | nulloptionalenabled_eventsarray<string>requiredEvent types to send, a whole group such as
contact.*, or["*"]for all.statusstringrequiredauto_disabledafter 3 days of failed deliveries or a410 Goneanswer.One of
enableddisabledauto_disableddisabled_reasonstring | nulloptionalsecret_previewstringoptionalsecretstringoptionalThe signing secret (
whsec_…). Returned only when the endpoint is created or its secret rotated. Store it now.created_atstring | nullrequiredupdated_atstring | nulloptional
Errors this can return1
- 404resource_missingNot found
Try it
curl -X POST https://api.saei.automize.sa/v1/webhook_endpoints/we_01j9x3k2m4n5p6q7r8s9t0v1w2/rotate_secret \
-H "Authorization: Bearer $API_KEY"The endpoint, with its new secret.
{
"id": "we_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_endpoint",
"livemode": false,
"url": "string",
"description": "string",
"enabled_events": [
"string"
],
"status": "enabled",
"disabled_reason": "string",
"secret_preview": "string",
"secret": "string",
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Send a test event
https://api.saei.automize.sa/v1/webhook_endpoints/{id}/test- Scope:
webhooks:write - Works in test mode
Sends a signed webhook.test event to this endpoint only. Check the delivery with the deliveries endpoint.
Path parameters
idstringrequiredThe object's id.
Response fields202· The test event was queued.
idstringrequiredobject"webhook_delivery"requiredlivemodebooleanrequiredwebhook_endpoint_idstringrequiredevent_idstringrequiredevent_typestringrequiredstatusstringrequiredfailedwill be retried atnext_attempt_at;deadwill not be retried again.One of
pendingsucceededfaileddeadattemptsintegerrequiredhttp_statusinteger | nulloptionalduration_msinteger | nulloptionalresponse_snippetstring | nulloptionallast_errorstring | nulloptionalnext_attempt_atstring | nulloptionaldelivered_atstring | nulloptionalcreated_atstring | nulloptionalpayloadobjectoptionalThe body of every webhook request.
data.objectis exactly the resource the REST API returns (e.g. amessage).Child fields (8)
idstringrequiredEvent id, also sent as the
webhook-idheader. The same on every retry, so use it to ignore duplicates.object"event"requiredtypestringrequiredversionstringrequiredPayload version. Fields are only ever added within a version.
created_atstringrequiredlivemodebooleanrequiredworkspace_idstringrequireddataobjectrequiredChild fields (2)
objectobjectrequiredprevious_attributesobjectoptionalThe values that changed, as they were before, when known.
Errors this can return2
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
Try it
curl -X POST https://api.saei.automize.sa/v1/webhook_endpoints/we_01j9x3k2m4n5p6q7r8s9t0v1w2/test \
-H "Authorization: Bearer $API_KEY"The test event was queued.
{
"id": "del_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "webhook_delivery",
"livemode": false,
"webhook_endpoint_id": "string",
"event_id": "string",
"event_type": "string",
"status": "pending",
"attempts": 0,
"http_status": 0,
"duration_ms": 0,
"response_snippet": "string",
"last_error": "string",
"next_attempt_at": "2026-10-01T09:30:00Z",
"delivered_at": "2026-10-01T09:30:00Z",
"created_at": "2026-10-01T09:30:00Z",
"payload": {
"id": "evt_01j9x3k2m4n5p6q7r8s9t0v1w2",
"object": "event",
"type": "message.delivered",
"version": "2",
"created_at": "2026-10-01T09:30:00Z",
"livemode": false,
"workspace_id": "ws_12",
"data": {
"object": {},
"previous_attributes": {}
}
}
}