Webhooks
Methods in this section: 8. All methods
GET /webhooks Available
#List subscriptions
The subscriptions of this integration (at most 10). The signing secret is not returned.
- Scopes
webhooks:manage
- Rate limit
- read
- Idempotency
- not required
- Successful response
200 A page of subscriptions.
Response body
| Field | Type | Description |
|---|
data | array<Webhook> required | |
next_cursor | string required, may be null | Cursor of the next page; null — the list is exhausted. Valid for 24 hours. |
Examples
Request
curl -X GET 'https://wfacademy.org/api/public/v1/webhooks' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY"
Response 200
{
"data": [
{
"id": "EXAMPLE_ID",
"url": "https://example.com/hooks/sapport",
"events": [
null
],
"include_pii": false,
"description": null,
"status": "active",
"created_at": "2026-10-11T09:00:00Z",
"updated_at": "2026-10-11T09:00:00Z",
"secret_rotated_at": null,
"previous_secret_expires_at": null
}
],
"next_cursor": "EXAMPLE_CURSOR"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing
POST /webhooks Available
#Create a subscription
Creates an event subscription. The signing secret is shown once, in this response. The URL goes through SSRF protection; include_pii: true is allowed only for lead.*, contact.* and conversation.* events.
- Scopes
webhooks:manage
- Rate limit
- write
- Idempotency
- Idempotency-Key is required
- Successful response
201 The subscription with its secret.
Parameters
| Field | Type | Description |
|---|
Idempotency-Key | string required | In: header. A unique string (usually a UUID v4), new for every new operation. A retry with the same key and body yields the same result. |
Request body Subscription parameters.
| Field | Type | Description |
|---|
url | string required | Receiving URL: https, port 443, a host name (not an IP), no redirects. |
events | array<string> required | Event types: an exact type or a family pattern "family.*". Available types: conversation.created, message.created, conversation.handoff_requested, conversation.summary_ready, lead.created, lead.updated, lead.scored, lead.status_changed, lead.action_requested, task.created, task.completed, contact.merged, crm.mode_changed, article.ready, article.published, article.generation.failed, strategist.report.ready, strategist.turn.completed, operation.completed, api_key.expiring. |
include_pii | boolean optional | Full payload with personal data; only for lead.*, contact.* and conversation.* events. Default false. |
description | string optional, may be null | A note for yourself, up to 200 characters. |
Response body
| Field | Type | Description |
|---|
id | string required | Subscription id. |
url | string required | Receiving URL: https, port 443, a host name (not an IP), no redirects. |
events | array<string> required | Event types: an exact type or a family pattern "family.*". Available types: conversation.created, message.created, conversation.handoff_requested, conversation.summary_ready, lead.created, lead.updated, lead.scored, lead.status_changed, lead.action_requested, task.created, task.completed, contact.merged, crm.mode_changed, article.ready, article.published, article.generation.failed, strategist.report.ready, strategist.turn.completed, operation.completed, api_key.expiring. |
include_pii | boolean required | Full payload with personal data; only for lead.*, contact.* and conversation.* events. Default false. |
description | string required, may be null | A note for yourself, up to 200 characters. |
status | string required | active — deliveries flow; paused — suspended. Values: active paused |
created_at | string required | ISO 8601 UTC. |
updated_at | string required | ISO 8601 UTC. |
secret_rotated_at | string required, may be null | Time of the last secret rotation; null — never rotated. |
previous_secret_expires_at | string required, may be null | While the rotation window (24 hours) is open — when the previous secret stops working; otherwise null. |
secret | string required, may be null | The signing secret: shown ONCE, in the creation or rotation response. On an idempotent replay of the request — null: keep the secret from the first response. |
Examples
Request
curl -X POST 'https://wfacademy.org/api/public/v1/webhooks' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY" \
-H 'Idempotency-Key: '"$(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/hooks/sapport",
"events": [
"string"
],
"include_pii": false,
"description": "string"
}'
Response 201
{
"id": "EXAMPLE_ID",
"url": "https://example.com/hooks/sapport",
"events": [
"string"
],
"include_pii": false,
"description": "string",
"status": "active",
"created_at": "2026-10-11T09:00:00Z",
"updated_at": "2026-10-11T09:00:00Z",
"secret_rotated_at": "2026-10-11T09:00:00Z",
"previous_secret_expires_at": "2026-10-11T09:00:00Z",
"secret": "string"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing pii_transfer_not_allowed bad_request validation_failed payload_too_large idempotency_key_required idempotency_conflict operation_in_progress invalid_state
GET /webhooks/{id} Available
#Get a subscription
The subscription without its secret.
- Scopes
webhooks:manage
- Rate limit
- read
- Idempotency
- not required
- Successful response
200 The subscription.
Parameters
| Field | Type | Description |
|---|
id | string required | In: path. Subscription id. |
Response body
| Field | Type | Description |
|---|
id | string required | Subscription id. |
url | string required | Receiving URL: https, port 443, a host name (not an IP), no redirects. |
events | array<string> required | Event types: an exact type or a family pattern "family.*". Available types: conversation.created, message.created, conversation.handoff_requested, conversation.summary_ready, lead.created, lead.updated, lead.scored, lead.status_changed, lead.action_requested, task.created, task.completed, contact.merged, crm.mode_changed, article.ready, article.published, article.generation.failed, strategist.report.ready, strategist.turn.completed, operation.completed, api_key.expiring. |
include_pii | boolean required | Full payload with personal data; only for lead.*, contact.* and conversation.* events. Default false. |
description | string required, may be null | A note for yourself, up to 200 characters. |
status | string required | active — deliveries flow; paused — suspended. Values: active paused |
created_at | string required | ISO 8601 UTC. |
updated_at | string required | ISO 8601 UTC. |
secret_rotated_at | string required, may be null | Time of the last secret rotation; null — never rotated. |
previous_secret_expires_at | string required, may be null | While the rotation window (24 hours) is open — when the previous secret stops working; otherwise null. |
Examples
Request
curl -X GET 'https://wfacademy.org/api/public/v1/webhooks/EXAMPLE_ID' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY"
Response 200
{
"id": "EXAMPLE_ID",
"url": "https://example.com/hooks/sapport",
"events": [
"string"
],
"include_pii": false,
"description": "string",
"status": "active",
"created_at": "2026-10-11T09:00:00Z",
"updated_at": "2026-10-11T09:00:00Z",
"secret_rotated_at": "2026-10-11T09:00:00Z",
"previous_secret_expires_at": "2026-10-11T09:00:00Z"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing not_found
PATCH /webhooks/{id} Available
#Update a subscription
Changes the URL, events, note, status (active or paused) and include_pii. Pass at least one field.
- Scopes
webhooks:manage
- Rate limit
- write
- Idempotency
- not required
- Successful response
200 The subscription after the update.
Parameters
| Field | Type | Description |
|---|
id | string required | In: path. Subscription id. |
Request body The fields to change.
| Field | Type | Description |
|---|
url | string optional | Receiving URL: https, port 443, a host name (not an IP), no redirects. |
events | array<string> optional | Event types: an exact type or a family pattern "family.*". Available types: conversation.created, message.created, conversation.handoff_requested, conversation.summary_ready, lead.created, lead.updated, lead.scored, lead.status_changed, lead.action_requested, task.created, task.completed, contact.merged, crm.mode_changed, article.ready, article.published, article.generation.failed, strategist.report.ready, strategist.turn.completed, operation.completed, api_key.expiring. |
include_pii | boolean optional | Full payload with personal data; only for lead.*, contact.* and conversation.* events. Default false. |
description | string optional, may be null | A note for yourself, up to 200 characters. |
status | string optional | Pause or resume deliveries. Values: active paused |
Response body
| Field | Type | Description |
|---|
id | string required | Subscription id. |
url | string required | Receiving URL: https, port 443, a host name (not an IP), no redirects. |
events | array<string> required | Event types: an exact type or a family pattern "family.*". Available types: conversation.created, message.created, conversation.handoff_requested, conversation.summary_ready, lead.created, lead.updated, lead.scored, lead.status_changed, lead.action_requested, task.created, task.completed, contact.merged, crm.mode_changed, article.ready, article.published, article.generation.failed, strategist.report.ready, strategist.turn.completed, operation.completed, api_key.expiring. |
include_pii | boolean required | Full payload with personal data; only for lead.*, contact.* and conversation.* events. Default false. |
description | string required, may be null | A note for yourself, up to 200 characters. |
status | string required | active — deliveries flow; paused — suspended. Values: active paused |
created_at | string required | ISO 8601 UTC. |
updated_at | string required | ISO 8601 UTC. |
secret_rotated_at | string required, may be null | Time of the last secret rotation; null — never rotated. |
previous_secret_expires_at | string required, may be null | While the rotation window (24 hours) is open — when the previous secret stops working; otherwise null. |
Examples
Request
curl -X PATCH 'https://wfacademy.org/api/public/v1/webhooks/EXAMPLE_ID' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/hooks/sapport",
"events": [
"string"
],
"include_pii": false,
"description": "string",
"status": "active"
}'
Response 200
{
"id": "EXAMPLE_ID",
"url": "https://example.com/hooks/sapport",
"events": [
"string"
],
"include_pii": false,
"description": "string",
"status": "active",
"created_at": "2026-10-11T09:00:00Z",
"updated_at": "2026-10-11T09:00:00Z",
"secret_rotated_at": "2026-10-11T09:00:00Z",
"previous_secret_expires_at": "2026-10-11T09:00:00Z"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing pii_transfer_not_allowed not_found bad_request validation_failed payload_too_large
DELETE /webhooks/{id} Available
#Delete a subscription
Deletes the subscription together with its delivery log. Deleting again returns not_found.
- Scopes
webhooks:manage
- Rate limit
- write
- Idempotency
- not required
- Successful response
204 The subscription is deleted; no body.
Parameters
| Field | Type | Description |
|---|
id | string required | In: path. Subscription id. |
Examples
Request
curl -X DELETE 'https://wfacademy.org/api/public/v1/webhooks/EXAMPLE_ID' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY"
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing not_found
POST /webhooks/{id}/rotate-secret Available
#Rotate the secret
Issues a new secret (shown once). Both secrets are valid for 24 hours and every delivery is signed with both.
- Scopes
webhooks:manage
- Rate limit
- write
- Idempotency
- Idempotency-Key is required
- Successful response
200 The subscription with the new secret.
Parameters
| Field | Type | Description |
|---|
id | string required | In: path. Subscription id. |
Idempotency-Key | string required | In: header. A unique string (usually a UUID v4), new for every new operation. A retry with the same key and body yields the same result. |
Response body
| Field | Type | Description |
|---|
id | string required | Subscription id. |
url | string required | Receiving URL: https, port 443, a host name (not an IP), no redirects. |
events | array<string> required | Event types: an exact type or a family pattern "family.*". Available types: conversation.created, message.created, conversation.handoff_requested, conversation.summary_ready, lead.created, lead.updated, lead.scored, lead.status_changed, lead.action_requested, task.created, task.completed, contact.merged, crm.mode_changed, article.ready, article.published, article.generation.failed, strategist.report.ready, strategist.turn.completed, operation.completed, api_key.expiring. |
include_pii | boolean required | Full payload with personal data; only for lead.*, contact.* and conversation.* events. Default false. |
description | string required, may be null | A note for yourself, up to 200 characters. |
status | string required | active — deliveries flow; paused — suspended. Values: active paused |
created_at | string required | ISO 8601 UTC. |
updated_at | string required | ISO 8601 UTC. |
secret_rotated_at | string required, may be null | Time of the last secret rotation; null — never rotated. |
previous_secret_expires_at | string required, may be null | While the rotation window (24 hours) is open — when the previous secret stops working; otherwise null. |
secret | string required, may be null | The signing secret: shown ONCE, in the creation or rotation response. On an idempotent replay of the request — null: keep the secret from the first response. |
Examples
Request
curl -X POST 'https://wfacademy.org/api/public/v1/webhooks/EXAMPLE_ID/rotate-secret' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY" \
-H 'Idempotency-Key: '"$(uuidgen)"
Response 200
{
"id": "EXAMPLE_ID",
"url": "https://example.com/hooks/sapport",
"events": [
"string"
],
"include_pii": false,
"description": "string",
"status": "active",
"created_at": "2026-10-11T09:00:00Z",
"updated_at": "2026-10-11T09:00:00Z",
"secret_rotated_at": "2026-10-11T09:00:00Z",
"previous_secret_expires_at": "2026-10-11T09:00:00Z",
"secret": "string"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing not_found idempotency_key_required idempotency_conflict operation_in_progress
POST /webhooks/{id}/test Available
#Send a test event
Queues a webhook.test event (livemode: false) for this subscription only. The subscription must be active.
- Scopes
webhooks:manage
- Rate limit
- write
- Idempotency
- Idempotency-Key is required
- Successful response
202 The event is queued.
Parameters
| Field | Type | Description |
|---|
id | string required | In: path. Subscription id. |
Idempotency-Key | string required | In: header. A unique string (usually a UUID v4), new for every new operation. A retry with the same key and body yields the same result. |
Response body
| Field | Type | Description |
|---|
event_id | string required, may be null | The test event id. |
type | string required | |
status | string required | The event is queued; it goes out on the next delivery run (within a minute). |
Examples
Request
curl -X POST 'https://wfacademy.org/api/public/v1/webhooks/EXAMPLE_ID/test' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY" \
-H 'Idempotency-Key: '"$(uuidgen)"
Response 202
{
"event_id": "EXAMPLE_ID",
"type": "string",
"status": "string"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing not_found invalid_state idempotency_key_required idempotency_conflict operation_in_progress
GET /webhooks/{id}/deliveries Available
#Delivery log
Delivery attempts of the subscription, newest first; kept for 30 days.
- Scopes
webhooks:manage
- Rate limit
- read
- Idempotency
- not required
- Successful response
200 A page of the log.
Parameters
| Field | Type | Description |
|---|
id | string required | In: path. Subscription id. |
limit | integer optional | In: query. Page size: 1 to 100, default 25. |
cursor | string optional | In: query. The next_cursor value from the previous response. Valid for 24 hours; start over when filters change. |
state | string optional | In: query. Filter by delivery state. |
Response body
| Field | Type | Description |
|---|
data | array<WebhookDelivery> required | |
next_cursor | string required, may be null | Cursor of the next page; null — the list is exhausted. Valid for 24 hours. |
Examples
Request
curl -X GET 'https://wfacademy.org/api/public/v1/webhooks/EXAMPLE_ID/deliveries' \
-H 'Authorization: Bearer '"$SAPPORT_API_KEY"
Response 200
{
"data": [
{
"id": "EXAMPLE_ID",
"event_id": "EXAMPLE_ID",
"state": "pending",
"attempt": 0,
"status_code": null,
"duration_ms": null,
"error": null,
"next_attempt_at": null,
"delivered_at": null,
"created_at": "2026-10-11T09:00:00Z"
}
],
"next_cursor": "EXAMPLE_CURSOR"
}
Error example
{
"type": "https://wfacademy.org/developers/errors#scope_missing",
"title": "Scope is missing",
"status": 403,
"code": "scope_missing",
"detail": "EXAMPLE",
"request_id": "req_EXAMPLE"
}
Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.
Possible errors
invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing not_found validation_failed