curl --request POST \
--url https://app.thinnest.ai/api/v1/webhooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent": "ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34",
"url": "https://crm.sunrisedental.in/hooks/agent",
"events": [
"call.analysed",
"lead.captured"
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent: 'ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34',
url: 'https://crm.sunrisedental.in/hooks/agent',
events: ['call.analysed', 'lead.captured']
})
};
fetch('https://app.thinnest.ai/api/v1/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.thinnest.ai/api/v1/webhooks"
payload = {
"agent": "ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34",
"url": "https://crm.sunrisedental.in/hooks/agent",
"events": ["call.analysed", "lead.captured"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "wh_e1c5a7d2-9b3f-4c86-a0e4-5d2b7f913c08",
"agent": "ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34",
"includeCustomers": false,
"url": "https://crm.sunrisedental.in/hooks/agent",
"events": [
"call.analysed",
"lead.captured"
],
"enabled": true,
"delivery": {
"failuresInARow": 0,
"lastStatus": null,
"lastError": null,
"lastSentAt": null
},
"createdAt": "2026-10-06T09:41:00.210Z",
"signingSecret": "q7Vb2LmX9cTz4RkP1sWd8HfN3yJe6GaU"
}{
"error": "`url` must start with https://."
}{
"error": "Send a valid API key as `Authorization: Bearer <key>`."
}{
"error": "This API key is read-only: it can read everything but change nothing."
}{
"error": "That agent was not found."
}{
"error": "Over 240 requests a minute. Slow down and retry."
}{
"error": "Could not add the endpoint."
}{
"error": "Webhooks are not available on this deployment yet."
}Create Webhook
Adds an endpoint for one agent’s events — or, from a developer workspace, with includeCustomers: true, one endpoint for every agent in every one of your customers, each delivery’s data carrying the workspaceId it is about. The response carries signingSecret once: store it to verify x-thinnest-signature on every delivery, because it is never shown again. url is an https:// address or an email address (a helpdesk that opens tickets by mail gets one email per event); addresses inside our own network are refused. A build key may do this.
curl --request POST \
--url https://app.thinnest.ai/api/v1/webhooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent": "ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34",
"url": "https://crm.sunrisedental.in/hooks/agent",
"events": [
"call.analysed",
"lead.captured"
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
agent: 'ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34',
url: 'https://crm.sunrisedental.in/hooks/agent',
events: ['call.analysed', 'lead.captured']
})
};
fetch('https://app.thinnest.ai/api/v1/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://app.thinnest.ai/api/v1/webhooks"
payload = {
"agent": "ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34",
"url": "https://crm.sunrisedental.in/hooks/agent",
"events": ["call.analysed", "lead.captured"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "wh_e1c5a7d2-9b3f-4c86-a0e4-5d2b7f913c08",
"agent": "ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34",
"includeCustomers": false,
"url": "https://crm.sunrisedental.in/hooks/agent",
"events": [
"call.analysed",
"lead.captured"
],
"enabled": true,
"delivery": {
"failuresInARow": 0,
"lastStatus": null,
"lastError": null,
"lastSentAt": null
},
"createdAt": "2026-10-06T09:41:00.210Z",
"signingSecret": "q7Vb2LmX9cTz4RkP1sWd8HfN3yJe6GaU"
}{
"error": "`url` must start with https://."
}{
"error": "Send a valid API key as `Authorization: Bearer <key>`."
}{
"error": "This API key is read-only: it can read everything but change nothing."
}{
"error": "That agent was not found."
}{
"error": "Over 240 requests a minute. Slow down and retry."
}{
"error": "Could not add the endpoint."
}{
"error": "Webhooks are not available on this deployment yet."
}Authorizations
Your API key (ta_live_…) from Settings → API keys, sent as Authorization: Bearer <key>. Keep it on a server: it can message every customer you have. A key is full, build or read-only; a request its level does not allow is refused with 403.
Headers
Developers only: the customer workspace this request acts in — its org_… id from POST /customers. Leave it out to act in your own workspace.
"org_3fKq9TzQ1mN8vB2xR7cLpA"
Body
An https:// URL, or an email address for a helpdesk that opens tickets by mail. Addresses inside our own network are refused.
"https://crm.sunrisedental.in/hooks/agent"
The agent whose events to send (ag_…). Required unless includeCustomers is true; never with it.
"ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34"
Developer workspaces only: one endpoint for the events of every agent in every one of your customers. Send it instead of agent.
false
Which events to send. Leave it out for every event, now and as new ones are added (the endpoint then reads ["*"]); naming all of them means the same.
1An event a webhook endpoint can subscribe to.
lead.captured, conversation.escalated, conversation.resolved, call.completed, call.analysed, campaign.finished ["call.analysed", "lead.captured"]
Whether to start sending at once.
true
Response
The endpoint, with its signing secret shown this once.
A new endpoint, with its signing secret.
The endpoint's id (wh_…).
"wh_e1c5a7d2-9b3f-4c86-a0e4-5d2b7f913c08"
The agent whose events it receives (ag_…); null for an endpoint that receives every customer's events (includeCustomers).
"ag_3f6a9c21-7d4e-4b58-9a1f-0c2e8b7d5a34"
Whether it receives the events of every agent in every one of this developer's customers, each delivery's data naming the customer as workspaceId.
false
Where events go: an https:// URL or an email address.
"https://crm.sunrisedental.in/hooks/agent"
The events it receives. ["*"] means every event, now and as new ones are added.
*, lead.captured, conversation.escalated, conversation.resolved, call.completed, call.analysed, campaign.finished ["call.analysed", "lead.captured"]
Whether events are sent to it. Turned off by itself after five failed deliveries in a row.
true
How delivering to it has gone.
Show child attributes
Show child attributes
"2026-09-17T09:41:00.210Z"
The secret every delivery's x-thinnest-signature is an HMAC-SHA256 under. In this response only — store it.
"q7Vb2LmX9cTz4RkP1sWd8HfN3yJe6GaU"