Webhooks
Configure webhook endpoints to receive real-time HTTP POST notifications when events occur in your workspace — such as incoming calls, call state changes, call endings, and contact updates.
For details on payload format, event types, retry policy, and signature verification, see the Webhooks Overview.
Endpoints​
| Method | Endpoint | Description |
|---|---|---|
GET | /webhooks | List all webhook endpoints |
GET | /webhooks/:id | Get webhook details |
POST | /webhooks | Create a webhook endpoint |
POST | /webhooks/:id/test-event | Send a test event |
PATCH | /webhooks/:id | Update a webhook endpoint |
DELETE | /webhooks/:id | Delete a webhook endpoint |
The Webhook Object​
| Field | Type | Description |
|---|---|---|
id | string | Unique webhook identifier (prefixed with wh-) |
workspace_id | string | Workspace identifier |
title | string | Display name for the webhook |
url | string | The URL that receives event notifications |
events | string[] | Array of event names this webhook is subscribed to |
headers | object[] | Custom HTTP headers sent with each delivery |
is_active | boolean | Whether the webhook is active |
secret | string | Signing secret for signature verification (only returned on creation) |
created_at | string | ISO 8601 creation timestamp |
updated_at | string | ISO 8601 last update timestamp |
Webhook Header Object​
| Field | Type | Description |
|---|---|---|
key | string | Header name (1–35 characters) |
value | string | Header value (1–255 characters) |
Available Event Names​
For complete payload structures and JSON schemas for each event, see the Webhook Event Catalog.
| Event | Description |
|---|---|
call.created | A new call has been initiated |
call.answered | A call was answered by an agent or user |
call.ended | A call has ended |
call.recording.ready | A call recording audio file has finished processing, uploaded, and is ready |
call.transcription.completed | Real-time call transcription and Named Entity Recognition (NER) completed |
contact.created | A new contact was created in the workspace |
contact.updated | An existing contact was updated |
contact.deleted | A contact was deleted |
agent.state | An agent's presence state was changed (available, busy, away, etc) |
agent.created | A new workspace agent account was created |
agent.updated | An existing workspace agent account was updated |
agent.deleted | A workspace agent account was deleted |
workspace.credit.updated | Workspace credit balance was updated (e.g., call charge deduction, top-up) |
List Webhooks​
GET /webhooks
Retrieve a paginated list of all webhook endpoints in the workspace.
Authentication​
Requires ApiKey with any scope.
Query Parameters​
| Parameter | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number (min: 1) |
limit | number | 10 | Items per page (min: 1, max: 100) |
search | string | — | Search by title |
sort_field | string | created_at | Sort field. Allowed: created_at |
sort_order | string | desc | Sort order: asc or desc |
Request​
curl -X GET "https://{workspace_id}.firetell.app/api/v1/webhooks?page=1&limit=10" \
-H "Authorization: ApiKey sk-YOUR_API_KEY"
Response​
{
"data": [
{
"id": "wh-7f3a2b1c9d4e5f6a8b0c1d2e",
"workspace_id": "yourcompany",
"title": "Call Events - Production",
"url": "https://api.example.com/webhooks/firetell",
"events": ["call.created", "call.ended"],
"headers": [
{
"key": "X-Custom-Token",
"value": "my-secret-token"
}
],
"is_active": true,
"created_at": "2026-01-15T08:30:00.000Z",
"updated_at": "2026-03-20T14:00:00.000Z"
},
{
"id": "wh-9a8b7c6d5e4f3a2b1c0d9e8f",
"workspace_id": "yourcompany",
"title": "Contact Sync",
"url": "https://crm.example.com/hooks/firetell",
"events": ["contact.created", "contact.updated", "contact.deleted"],
"headers": [],
"is_active": true,
"created_at": "2026-02-10T10:00:00.000Z",
"updated_at": "2026-02-10T10:00:00.000Z"
}
],
"meta": {
"total": 2,
"page": 1,
"limit": 10,
"total_pages": 1
}
}
The secret field is not included in list responses. It is only returned when creating a webhook.
Get Webhook​
GET /webhooks/:id
Retrieve details of a specific webhook endpoint.
Authentication​
Requires ApiKey with full scope.
Path Parameters​
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook ID (e.g., wh-7f3a2b1c9d4e5f6a8b0c1d2e) |
Request​
curl -X GET "https://{workspace_id}.firetell.app/api/v1/webhooks/wh-7f3a2b1c9d4e5f6a8b0c1d2e" \
-H "Authorization: ApiKey sk-YOUR_API_KEY"
Response​
{
"id": "wh-7f3a2b1c9d4e5f6a8b0c1d2e",
"workspace_id": "yourcompany",
"title": "Call Events - Production",
"url": "https://api.example.com/webhooks/firetell",
"events": ["call.created", "call.ended"],
"headers": [
{
"key": "X-Custom-Token",
"value": "my-secret-token"
}
],
"is_active": true,
"created_at": "2026-01-15T08:30:00.000Z",
"updated_at": "2026-03-20T14:00:00.000Z"
}
Error Response​
{
"statusCode": 404,
"message": "item not found",
"error": "Not Found"
}
Create Webhook​
POST /webhooks
Create a new webhook endpoint. A signing secret is automatically generated and returned in the response — save it securely, as it will not be retrievable again.
Authentication​
Requires ApiKey with full scope.
Each workspace is limited to a maximum of 20 webhook endpoints. Exceeding this limit will return a 403 Forbidden error.
Request Body​
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✅ | Display name. 1–100 characters. |
url | string | ✅ | Webhook URL. Must be a valid HTTPS URL. Max 255 characters. |
events | string[] | ✅ | Array of event names to subscribe to. At least 1 event required. |
headers | object[] | — | Custom HTTP headers (max 3). Each with key (1–35 chars) and value (1–255 chars). |
Request​
curl -X POST "https://{workspace_id}.firetell.app/api/v1/webhooks" \
-H "Authorization: ApiKey sk-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Call Events - Production",
"url": "https://api.example.com/webhooks/firetell",
"events": ["call.created", "call.answered", "call.ended"],
"headers": [
{
"key": "X-Custom-Token",
"value": "my-secret-token"
}
]
}'
Response​
{
"id": "wh-d4e5f6a7b8c9d0e1f2a3b4c5",
"workspace_id": "yourcompany",
"title": "Call Events - Production",
"url": "https://api.example.com/webhooks/firetell",
"events": ["call.created", "call.answered", "call.ended"],
"headers": [
{
"key": "X-Custom-Token",
"value": "my-secret-token"
}
],
"is_active": true,
"secret": "whse-a1b2c3d4e5f6a7b8c9d0e1",
"created_at": "2026-07-09T08:00:00.000Z",
"updated_at": "2026-07-09T08:00:00.000Z"
}
Save the secret value immediately. The secret (prefixed with whse-) is only returned once during creation. You will need it to verify webhook signatures using HMAC-SHA256.
Error Response​
Webhook limit reached:
{
"statusCode": 403,
"message": "We currently only support up to 20 webhooks with your plan. You've reached your limit.",
"error": "Forbidden"
}
Send Test Event​
POST /webhooks/:id/test-event
Send a simulated test event to verify your webhook endpoint is working correctly. The test payload is sent immediately to the configured URL with a valid signature.
Authentication​
Requires ApiKey with full scope.
Path Parameters​
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook ID |
Request Body​
| Field | Type | Required | Description |
|---|---|---|---|
event_name | string | ✅ | The event type to simulate. Must be one of the events the webhook is subscribed to. |
Request​
curl -X POST "https://{workspace_id}.firetell.app/api/v1/webhooks/wh-7f3a2b1c9d4e5f6a8b0c1d2e/test-event" \
-H "Authorization: ApiKey sk-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_name": "call.created"
}'
Success Response​
{
"success": true,
"status": 200,
"status_text": "OK",
"latency_ms": 142,
"message": "Webhook test event with respond success"
}
Failure Responses​
Endpoint returned non-success status:
{
"success": false,
"status": 500,
"status_text": "Internal Server Error",
"latency_ms": 85,
"error": "Internal Server Error",
"message": "Webhook endpoint did not respond success. status >= 300"
}
Endpoint unreachable:
{
"success": false,
"status": 0,
"latency_ms": 0,
"error": "ECONNREFUSED",
"message": "Webhook endpoint did not respond"
}
Event not subscribed:
{
"statusCode": 400,
"message": "This endpoint is not currently subscribed to this event",
"error": "Bad Request"
}
Test Payload Example​
When simulating a call.created event, the following test payload is sent to your URL:
{
"event": "call.created",
"data": {
"workspace_id": "yourcompany",
"call_id": "test_call_id_1720512000000",
"direction": "inbound",
"caller": {
"name": "Caller_name",
"number": "Caller_number"
},
"callee": {
"name": "Callee_name",
"number": "Callee_number"
},
"created_at": "2026-07-09T08:00:00.000Z"
}
}
Use the test event endpoint during development to verify your webhook handler is correctly parsing payloads and validating signatures before going live.
Update Webhook​
PATCH /webhooks/:id
Update an existing webhook endpoint's configuration. All fields in the request body are required — this endpoint replaces the webhook configuration entirely.
Authentication​
Requires ApiKey with full scope.
Path Parameters​
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook ID |
Request Body​
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✅ | Display name. 1–100 characters. |
url | string | ✅ | Webhook URL. Must be a valid HTTPS URL. Max 255 characters. |
events | string[] | ✅ | Array of event names. At least 1 event required. |
headers | object[] | — | Custom HTTP headers (max 3). |
Request​
curl -X PATCH "https://{workspace_id}.firetell.app/api/v1/webhooks/wh-7f3a2b1c9d4e5f6a8b0c1d2e" \
-H "Authorization: ApiKey sk-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Call Events - Updated",
"url": "https://api.example.com/webhooks/firetell-v2",
"events": ["call.created", "call.ended"],
"headers": []
}'
Response​
Returns the updated webhook object:
{
"id": "wh-7f3a2b1c9d4e5f6a8b0c1d2e",
"workspace_id": "yourcompany",
"title": "Call Events - Updated",
"url": "https://api.example.com/webhooks/firetell-v2",
"events": ["call.created", "call.ended"],
"headers": [],
"is_active": true,
"created_at": "2026-01-15T08:30:00.000Z",
"updated_at": "2026-07-09T09:30:00.000Z"
}
Updating a webhook does not regenerate the signing secret. The original secret remains valid.
Error Response​
{
"statusCode": 404,
"message": "item not found",
"error": "Not Found"
}
Delete Webhook​
DELETE /webhooks/:id
Permanently delete a webhook endpoint. Event notifications will immediately stop being delivered to this URL.
Authentication​
Requires ApiKey with full scope.
This action is irreversible. Any events that occur after deletion will not be delivered to this endpoint.
Path Parameters​
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook ID |
Request​
curl -X DELETE "https://{workspace_id}.firetell.app/api/v1/webhooks/wh-7f3a2b1c9d4e5f6a8b0c1d2e" \
-H "Authorization: ApiKey sk-YOUR_API_KEY"
Response​
Returns the deleted webhook object:
{
"id": "wh-7f3a2b1c9d4e5f6a8b0c1d2e",
"workspace_id": "yourcompany",
"title": "Call Events - Production",
"url": "https://api.example.com/webhooks/firetell",
"events": ["call.created", "call.ended"],
"headers": [],
"is_active": true,
"created_at": "2026-01-15T08:30:00.000Z",
"updated_at": "2026-03-20T14:00:00.000Z"
}
Error Response​
{
"statusCode": 404,
"message": "item not found",
"error": "Not Found"
}
Webhook Delivery​
Signature Verification​
Every webhook delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the request body, signed with your webhook's secret.
const crypto = require("crypto");
function verifyWebhookSignature(rawBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
// In your Express handler:
app.post("/webhooks/firetell", (req, res) => {
const signature = req.headers["x-webhook-signature"];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
"whse-your-webhook-secret",
);
if (!isValid) {
return res.status(401).send("Invalid signature");
}
// Process the event...
res.status(200).send("OK");
});
Delivery Headers​
Each webhook delivery includes the following headers:
| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Webhook-Signature | HMAC-SHA256 signature of the request body |
X-Powered-By | Firetell service identifier |
User-Agent | Firetell webhook delivery agent (e.g., region@firetell.shared.webhook/1.0.2) |
| Custom headers | Any headers you configured on the webhook endpoint |
Timeout & Retries​
- Timeout: 5 seconds per delivery attempt
- Redirect: Not followed (
maxRedirects: 0) - Your endpoint must respond with a status code below 300 to be considered successful
- See Webhooks Overview for the retry policy