Webhooks API
Webhooks API
Manage webhook endpoints and view delivery history programmatically.
Endpoints Overview
| Method | Endpoint | Description |
|---|---|---|
| GET | /api-v1-webhooks | List all webhooks |
| GET | /api-v1-webhooks/:id | Get a single webhook |
| POST | /api-v1-webhooks | Create a new webhook |
| PATCH | /api-v1-webhooks/:id | Update a webhook |
| DELETE | /api-v1-webhooks/:id | Delete a webhook |
| GET | /api-v1-webhooks/:id/deliveries | List delivery history |
| POST | /api-v1-webhooks/:id/test | Send a test event |
| POST | /api-v1-webhooks/:id/deliveries/:deliveryId/retry | Retry a failed delivery |
Required Scopes
- Read operations:
read:webhooks - Write operations:
write:webhooks
List Webhooks
List all webhook endpoints for your company.
Endpoint: GET /api-v1-webhooks
Scope: read:webhooks
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Number of records per page (max: 100) |
page | integer | 1 | Page number |
is_active | boolean | - | Filter by active status |
Response
{ "data": [ { "id": "whk_550e8400-e29b-41d4-a716-446655440000", "name": "Production Webhook", "description": "Sends events to our backend", "url": "https://api.example.com/webhooks/sellercockpit", "events": ["contact.created", "contact.updated", "deal.stage_changed"], "is_active": true, "headers": { "X-Custom-Header": "my-value" }, "max_retries": 5, "total_deliveries": 1250, "successful_deliveries": 1230, "failed_deliveries": 20, "last_triggered_at": "2024-01-15T10:30:00Z", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-15T10:30:00Z" } ], "pagination": { "total": 3, "limit": 50, "page": 1, "has_more": false }}Example Request
curl -X GET "https://your-project.supabase.co/functions/v1/api-v1-webhooks" \ -H "Authorization: Bearer YOUR_API_KEY"Get Single Webhook
Retrieve a single webhook by its ID.
Endpoint: GET /api-v1-webhooks/:id
Scope: read:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
Response
{ "data": { "id": "whk_550e8400-e29b-41d4-a716-446655440000", "name": "Production Webhook", "description": "Sends events to our backend", "url": "https://api.example.com/webhooks/sellercockpit", "events": ["contact.created", "contact.updated", "deal.stage_changed"], "is_active": true, "headers": { "X-Custom-Header": "my-value" }, "max_retries": 5, "total_deliveries": 1250, "successful_deliveries": 1230, "failed_deliveries": 20, "last_triggered_at": "2024-01-15T10:30:00Z", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-15T10:30:00Z" }}Note: The secret field is never returned in GET responses for security.
Example Request
curl -X GET "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer YOUR_API_KEY"Create Webhook
Create a new webhook endpoint.
Endpoint: POST /api-v1-webhooks
Scope: write:webhooks
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the webhook |
url | string | Yes | HTTPS URL to receive events |
events | string[] | Yes | Array of event types to subscribe to |
description | string | No | Optional description |
headers | object | No | Custom HTTP headers to include |
is_active | boolean | No | Whether webhook is active (default: true) |
max_retries | integer | No | Max retry attempts (default: 5, max: 10) |
Available Events
contact.created, contact.updated, contact.deletedorganization.created, organization.updated, organization.deleteddeal.created, deal.updated, deal.stage_changed, deal.deletedactivity.createdtask.created, task.completedResponse
Returns the created webhook with the secret (shown only once).
{ "data": { "id": "whk_550e8400-e29b-41d4-a716-446655440000", "name": "Production Webhook", "description": "Sends events to our backend", "url": "https://api.example.com/webhooks/sellercockpit", "events": ["contact.created", "contact.updated"], "secret": "whsec_abc123def456...", "is_active": true, "headers": {}, "max_retries": 5, "created_at": "2024-01-15T10:30:00Z" }}Important: Save the secret immediately. It will not be shown again.
Example Request
curl -X POST "https://your-project.supabase.co/functions/v1/api-v1-webhooks" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Production Webhook", "url": "https://api.example.com/webhooks/sellercockpit", "events": ["contact.created", "contact.updated", "deal.stage_changed"], "description": "Sends events to our backend", "headers": { "X-Custom-Header": "my-value" } }'Error Responses
400 Validation Error (invalid URL):
{ "error": { "code": "VALIDATION_ERROR", "message": "URL must use HTTPS protocol" }}400 Validation Error (invalid event):
{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid event type: contact.invalid" }}Update Webhook
Update an existing webhook. Only provided fields will be updated.
Endpoint: PATCH /api-v1-webhooks/:id
Scope: write:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
Request Body
All fields are optional.
| Field | Type | Description |
|---|---|---|
name | string | Display name |
url | string | HTTPS endpoint URL |
events | string[] | Event subscriptions (replaces existing) |
description | string | Description |
headers | object | Custom headers (replaces existing) |
is_active | boolean | Active status |
max_retries | integer | Max retry attempts |
Response
{ "data": { "id": "whk_550e8400-e29b-41d4-a716-446655440000", "name": "Updated Webhook Name", "url": "https://api.example.com/webhooks/sellercockpit", "events": ["contact.created", "deal.created"], "is_active": true, "updated_at": "2024-01-16T14:20:00Z" }}Example Request
curl -X PATCH "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Updated Webhook Name", "events": ["contact.created", "deal.created"], "is_active": false }'Delete Webhook
Delete a webhook endpoint. All pending deliveries will be cancelled.
Endpoint: DELETE /api-v1-webhooks/:id
Scope: write:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
Response
{ "data": { "deleted": true }}Example Request
curl -X DELETE "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer YOUR_API_KEY"List Deliveries
View delivery history for a webhook.
Endpoint: GET /api-v1-webhooks/:id/deliveries
Scope: read:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Records per page (max: 100) |
page | integer | 1 | Page number |
status | string | - | Filter by status: pending, success, retrying, failed |
Response
{ "data": [ { "id": "del_660e8400-e29b-41d4-a716-446655440001", "webhook_id": "whk_550e8400-e29b-41d4-a716-446655440000", "event_type": "contact.created", "event_id": "evt_abc123", "status": "success", "response_code": 200, "response_body": "{\"received\": true}", "attempts": 1, "max_attempts": 5, "request_duration_ms": 245, "created_at": "2024-01-15T10:30:00Z", "delivered_at": "2024-01-15T10:30:01Z", "payload": { "id": "evt_abc123", "event": "contact.created", "created_at": "2024-01-15T10:30:00Z", "data": { "id": "...", "first_name": "John" } } }, { "id": "del_770e8400-e29b-41d4-a716-446655440002", "webhook_id": "whk_550e8400-e29b-41d4-a716-446655440000", "event_type": "deal.stage_changed", "event_id": "evt_def456", "status": "failed", "response_code": 500, "response_body": "Internal Server Error", "attempts": 5, "max_attempts": 5, "request_duration_ms": 30000, "created_at": "2024-01-14T09:00:00Z", "next_retry_at": null } ], "pagination": { "total": 150, "limit": 50, "page": 1, "has_more": true }}Delivery Status Values
| Status | Description |
|---|---|
pending | Queued, not yet attempted |
success | Delivered successfully (2xx response) |
retrying | Failed, scheduled for retry |
failed | All retry attempts exhausted |
Example Request
curl -X GET "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000/deliveries?status=failed&limit=20" \ -H "Authorization: Bearer YOUR_API_KEY"Send Test Event
Send a test webhook to verify your endpoint configuration.
Endpoint: POST /api-v1-webhooks/:id/test
Scope: write:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
Response
Returns the delivery result immediately (synchronous).
{ "data": { "success": true, "delivery_id": "del_880e8400-e29b-41d4-a716-446655440003", "response_code": 200, "response_body": "{\"received\": true}", "duration_ms": 156 }}Failed test:
{ "data": { "success": false, "delivery_id": "del_880e8400-e29b-41d4-a716-446655440003", "response_code": 500, "response_body": "Internal Server Error", "duration_ms": 2500 }}Test Payload
The test event sends this payload:
{ "id": "evt_test_123", "event": "test.webhook", "created_at": "2024-01-15T10:30:00.000Z", "api_version": "2025-12-01", "data": { "message": "This is a test webhook delivery", "webhook_id": "whk_550e8400-e29b-41d4-a716-446655440000" }}Example Request
curl -X POST "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000/test" \ -H "Authorization: Bearer YOUR_API_KEY"Retry Failed Delivery
Manually retry a failed webhook delivery.
Endpoint: POST /api-v1-webhooks/:id/deliveries/:deliveryId/retry
Scope: write:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
deliveryId | UUID | Yes | Delivery ID |
Response
{ "data": { "success": true, "message": "Delivery queued for retry" }}Error Responses
400 Already Successful:
{ "error": { "code": "INVALID_REQUEST", "message": "Delivery already succeeded, cannot retry" }}404 Not Found:
{ "error": { "code": "NOT_FOUND", "message": "Delivery not found" }}Example Request
curl -X POST "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000/deliveries/del_770e8400-e29b-41d4-a716-446655440002/retry" \ -H "Authorization: Bearer YOUR_API_KEY"Regenerate Secret
Generate a new webhook secret. The old secret is immediately invalidated.
Endpoint: POST /api-v1-webhooks/:id/regenerate-secret
Scope: write:webhooks
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Webhook ID |
Response
{ "data": { "id": "whk_550e8400-e29b-41d4-a716-446655440000", "secret": "whsec_newSecretValue123..." }}Important: Update your server immediately with the new secret.
Example Request
curl -X POST "https://your-project.supabase.co/functions/v1/api-v1-webhooks/whk_550e8400-e29b-41d4-a716-446655440000/regenerate-secret" \ -H "Authorization: Bearer YOUR_API_KEY"Multi-Tenant Isolation
All webhooks are automatically scoped to your company. You can only access webhooks that belong to your company (determined by your API key’s company_id).
Related Resources
- Webhooks Overview - Concepts, payload format, and security
- Authentication - API key management
- Rate Limits - Usage limits