Webhook Setup
Webhooks send HTTP POST requests to your server when events occur in SendSeven -- a message is received, a conversation is closed, a contact is created, and more. This enables real-time integrations without polling the API.
Required Scopes
| Scope | Purpose |
|---|---|
webhooks:read | List and view webhooks |
webhooks:create | Create new webhook endpoints |
webhooks:update | Update webhook configuration |
webhooks:delete | Delete webhooks |
How Webhooks Work
- You register a webhook endpoint URL and select events to subscribe to
- When a subscribed event occurs, SendSeven sends an HTTP POST to your URL
- Your server processes the event and returns a 2xx status code to acknowledge receipt
- If delivery fails, SendSeven retries with exponential backoff
Endpoint Requirements
Your webhook endpoint must:
- Use HTTPS (HTTP endpoints are not accepted)
- Return a 2xx status code within 30 seconds
- Accept POST requests with a JSON body
- Be publicly accessible from the internet
Create a Webhook
POST /api/v1/webhook-endpoints
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | User-friendly name for the webhook (1-255 chars) |
url | string | Yes | HTTPS endpoint URL |
subscribed_events | array | Yes | Array of event types to subscribe to |
authorization_header | string | No | Authorization header value (e.g., Bearer token123) |
retry_strategy | string | No | exponential (default), linear, or none |
max_retries | integer | No | Max retry attempts (default: 8, max: 15) |
timeout_seconds | integer | No | Request timeout in seconds (default: 30, 5-60) |
source_filter_mode | string | No | all (default) receives events from every channel; selected restricts them to the channels/integrations below |
filtered_channel_ids | array | No | Channel IDs to receive events from (only used when source_filter_mode is selected) |
filtered_email_integration_ids | array | No | Email integration IDs to receive events from (only used when source_filter_mode is selected) |
curl
curl -X POST "https://api.sendseven.com/api/v1/webhook-endpoints" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"name": "CRM Integration",
"url": "https://yourapp.com/webhooks/sendseven",
"subscribed_events": [
"message.received",
"message.sent",
"conversation.created",
"conversation.closed",
"contact.created"
]
}'
Response (201 Created)
Creation returns the signing secret, not the full endpoint object. Note the field name: it is webhook_id, not id.
{
"webhook_id": "wh_abc123",
"secret_key": "whsec_9f2c4b8e1d6a7053ef4c1b9a8d2e6f30",
"message": "Store this secret key securely. It will not be shown again."
}
secret_key nowThis is the only time the secret is ever returned. You need it to verify webhook signatures, and it cannot be retrieved later -- only replaced via POST /api/v1/webhook-endpoints/{webhook_id}/regenerate-secret, which invalidates the old one.
Use the returned webhook_id with GET /api/v1/webhook-endpoints/{webhook_id} if you need the full endpoint object (its own id field carries the same value).
List Webhooks
GET /api/v1/webhook-endpoints
curl -X GET "https://api.sendseven.com/api/v1/webhook-endpoints" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"
This endpoint returns a bare JSON array of endpoint objects -- there is no items / pagination envelope, because a tenant's webhook list is small and unpaginated:
[
{
"id": "wh_abc123",
"tenant_id": "tenant_xyz",
"name": "CRM Integration",
"url": "https://yourapp.com/webhooks/sendseven",
"has_authorization_header": false,
"subscribed_events": [
"message.received",
"message.sent",
"conversation.created",
"conversation.closed",
"contact.created"
],
"source_filter_mode": "all",
"filtered_channel_ids": null,
"filtered_email_integration_ids": null,
"is_active": true,
"is_verified": false,
"retry_strategy": "exponential",
"max_retries": 8,
"timeout_seconds": 30,
"last_success_at": "2026-02-10T18:04:11Z",
"last_failure_at": null,
"last_error": null,
"consecutive_failures": 0,
"created_at": "2026-02-10T18:00:00Z",
"updated_at": null
}
]
Update a Webhook
Update a webhook's URL, events, or active status. Only include the fields you want to change.
PATCH /api/v1/webhook-endpoints/{webhook_id}
| Field | Type | Description |
|---|---|---|
name | string | Updated name |
url | string | Updated endpoint URL |
subscribed_events | array | Updated event subscriptions (replaces existing list) |
is_active | boolean | Enable or disable the webhook |
authorization_header | string | Updated auth header (empty string to remove) |
curl -X PATCH "https://api.sendseven.com/api/v1/webhook-endpoints/wh_crm_sync" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"subscribed_events": [
"contact.created",
"contact.updated",
"conversation.created",
"conversation.closed",
"message.received"
]
}'
Updating subscribed_events replaces the entire event list. Include all events you want to subscribe to, not just the new ones.
Delete a Webhook
DELETE /api/v1/webhook-endpoints/{webhook_id}
curl -X DELETE "https://api.sendseven.com/api/v1/webhook-endpoints/wh_analytics" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00"
View Delivery History
Check delivery status and response times for a webhook:
GET /api/v1/webhook-endpoints/{webhook_id}/deliveries
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
page_size | integer | 50 | Items per page (1--100) |
status | string | -- | pending, success, failed, retrying, dead_letter, or queued (stored while the endpoint is suspended -- see Circuit breaker) |
event_type | string | -- | e.g. message.sent, conversation.created |
curl -X GET "https://api.sendseven.com/api/v1/webhook-endpoints/wh_crm_sync/deliveries?page=1&page_size=10" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"
This endpoint's pagination fields are flat (total, page, page_size, has_more) rather than nested under a pagination object:
{
"items": [
{
"id": "del_001",
"tenant_id": "tenant_xyz",
"webhook_endpoint_id": "wh_crm_sync",
"event_type": "contact.created",
"event_id": "evt_5f1c9d",
"attempt_number": 1,
"status": "success",
"response_status_code": 200,
"response_time_ms": 145,
"error_message": null,
"next_retry_at": null,
"created_at": "2026-02-10T17:30:00Z",
"completed_at": "2026-02-10T17:30:00Z",
"can_retry": false
},
{
"id": "del_002",
"tenant_id": "tenant_xyz",
"webhook_endpoint_id": "wh_crm_sync",
"event_type": "message.received",
"event_id": "evt_7a3b2e",
"attempt_number": 3,
"status": "failed",
"response_status_code": 500,
"response_time_ms": 2300,
"error_message": "Internal Server Error",
"next_retry_at": null,
"created_at": "2026-02-10T17:35:00Z",
"completed_at": "2026-02-10T17:35:02Z",
"can_retry": true
}
],
"total": 156,
"page": 1,
"page_size": 10,
"has_more": true
}
Deliveries with can_retry: true (status failed or dead_letter) can be replayed manually -- see the retry endpoint below.
Retry Policy
If your endpoint returns a non-2xx status code or times out, SendSeven retries. With the default exponential strategy, the delay before each retry grows and then caps at 30 minutes:
| Retry | Delay after the failed attempt |
|---|---|
| 1st retry | 5 seconds |
| 2nd retry | 10 seconds |
| 3rd retry | 30 seconds |
| 4th retry | 2 minutes |
| 5th retry | 5 minutes |
| 6th retry | 10 minutes |
| 7th retry and beyond | 30 minutes (capped) |
Retries continue until max_retries attempts have been made (default 8, configurable 0–15). With linear strategy, retries are spaced a fixed 60 seconds apart; with none, no retries are attempted. After the retry budget is exhausted, the delivery is marked as permanently failed.
Manually retry a delivery
A delivery whose can_retry is true (status failed or dead_letter) can be replayed on demand. This creates a new delivery attempt; the original row is left in place for audit.
POST /api/v1/webhook-endpoints/{webhook_id}/deliveries/{delivery_id}/retry
Required Scope: webhooks:update
curl -X POST "https://api.sendseven.com/api/v1/webhook-endpoints/wh_crm_sync/deliveries/del_002/retry" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00"
{
"success": true,
"delivery_id": "del_009",
"previous_delivery_id": "del_002",
"message": "Delivery queued for retry"
}
Circuit breaker: suspension, not silent loss
If a webhook accumulates 20 consecutive failures, SendSeven suspends it for a bounded 12-hour window rather than disabling it outright. During suspension:
- Matching events are not dropped — they are stored as
queueddeliveries (up to 10,000 per endpoint) and replayed in original order once the endpoint recovers. - SendSeven re-verifies your endpoint automatically on an escalating schedule: 1m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h after suspension.
- You receive email notifications across the lifecycle (suspended, reactivated, permanently disabled).
The endpoint's state is visible on the endpoint object: suspended_at is set while suspended, next_reactivation_at holds the next automatic check, and reactivation_attempts counts checks made so far.
| Outcome | What happens |
|---|---|
| A re-verification succeeds (automatic or triggered by you) | is_active returns to true, suspended_at clears, and the queued backlog is replayed in created_at order |
| The final check at +12h still fails | The endpoint is permanently deactivated and the queued deliveries are moved to dead_letter |
To recover immediately without waiting for the next scheduled check, fix your endpoint and trigger verification yourself:
curl -X POST "https://api.sendseven.com/api/v1/webhook-endpoints/wh_abc123/verify" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00"
A successful verification reactivates the endpoint and starts the replay. If the endpoint was permanently deactivated after the 12-hour window, re-enable it with PATCH .../{webhook_id} and {"is_active": true} — but note that its queued events were already dead-lettered by then.
Error Responses
| Status | Error Code | Description |
|---|---|---|
| 401 | INVALID_TOKEN | Token is invalid or expired |
| 403 | INSUFFICIENT_SCOPE | Token lacks required webhooks scope |
| 404 | RESOURCE_NOT_FOUND | Webhook ID does not exist or belongs to another tenant |
| 422 | VALIDATION_ERROR | Invalid URL or events list |
Next Steps
- Webhook Events Reference -- all available event types and payload formats
- Signature Verification -- secure your webhook endpoint