Reference
Webhook Endpoints (outbound)
Manage destinations that receive event notifications from the CRM. Each endpoint subscribes to one or more event names; events are delivered as signed HTTPS POST requests (see the Webhooks & Public Tracking appendix at the bottom of this page for the envelope, signature scheme, and retry policy).
The secret is auto-generated on create and is the HMAC-SHA256 key used to
sign every delivery. Treat it like a password — it is returned only on the
initial create response and on show; rotate by deleting and recreating.
List webhook endpoints
Lists the webhook endpoints this account has registered, newest first, with the events each one is subscribed to and whether it is active.
GET
/api/webhook-endpoints
Call it before registering another one: duplicated endpoints are the usual reason somebody receives the same event twice and blames the retry policy. Secrets are never included — they are shown once, at creation.
Query parameters
-
location_idintegerScope to a location.
Example:
1 -
is_activebooleanFilter active vs disabled.
Example:
true -
per_pageintegerRows per page. Default 20, maximum 100. See Lists, paging and filters.
Example:
20
curl --request GET \
--get "https://klozzo.com/api/webhook-endpoints?location_id=1&is_active=1&per_page=20" \
--header "Authorization: Bearer {YOUR_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://klozzo.com/api/webhook-endpoints"
);
const params = {
"location_id": "1",
"is_active": "1",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_API_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://klozzo.com/api/webhook-endpoints';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_API_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'location_id' => '1',
'is_active' => '1',
'per_page' => '20',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json
url = 'https://klozzo.com/api/webhook-endpoints'
params = {
'location_id': '1',
'is_active': '1',
'per_page': '20',
}
headers = {
'Authorization': 'Bearer {YOUR_API_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()
{
"data": [
{
"id": null,
"location_id": null,
"url": "https://example.test/webhooks/9MTvekde",
"events": [
"contact.created",
"message.received"
],
"is_active": true,
"last_delivery_at": null,
"created_at": null,
"updated_at": null
},
{
"id": null,
"location_id": null,
"url": "https://example.test/webhooks/KcUoSJav",
"events": [
"contact.created",
"message.received"
],
"is_active": true,
"last_delivery_at": null,
"created_at": null,
"updated_at": null
}
],
"links": {
"first": "/?page=1",
"last": "/?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "/?page=1",
"label": "1",
"page": 1,
"active": true
},
{
"url": null,
"label": "Next »",
"page": null,
"active": false
}
],
"path": "/",
"per_page": 20,
"to": 2,
"total": 2
}
}
-
dataobject[]-
idstring -
location_idstring -
urlstring -
eventsstring[] -
is_activeboolean -
last_delivery_atstring -
created_atstring -
updated_atstring
-
-
linksobject-
firststring -
laststring -
prevstring -
nextstring
-
-
metaobject-
current_pageinteger -
frominteger -
last_pageinteger -
linksobject[]-
urlstring -
labelstring -
pagestring -
activeboolean
-
-
pathstring -
per_pageinteger -
tointeger -
totalinteger
-
Register a webhook endpoint
Returns the new endpoint including a freshly generated secret. Save
this secret immediately: it is only returned on this create call and on
subsequent show/index calls if the endpoint is still active.
POST
/api/webhook-endpoints
Body parameters
-
location_idintegerScope to a location.
Example:
1 -
urlstring requiredHTTPS URL that will receive POST deliveries (max 2048 chars).
Example:
https://hooks.example.com/herd -
eventsstring[] requiredEvent names this endpoint subscribes to. At least one.
Example:
["contact.created","contact.updated"] -
is_activebooleanDefault true.
Example:
true
curl --request POST \
"https://klozzo.com/api/webhook-endpoints" \
--header "Authorization: Bearer {YOUR_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"location_id\": 1,
\"url\": \"https:\\/\\/hooks.example.com\\/herd\",
\"events\": [
\"contact.created\",
\"contact.updated\"
],
\"is_active\": true
}"
const url = new URL(
"https://klozzo.com/api/webhook-endpoints"
);
const headers = {
"Authorization": "Bearer {YOUR_API_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"location_id": 1,
"url": "https:\/\/hooks.example.com\/herd",
"events": [
"contact.created",
"contact.updated"
],
"is_active": true
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://klozzo.com/api/webhook-endpoints';
$response = $client->post(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_API_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'location_id' => 1,
'url' => 'https://hooks.example.com/herd',
'events' => ['contact.created', 'contact.updated'],
'is_active' => true,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json
url = 'https://klozzo.com/api/webhook-endpoints'
payload = {
"location_id": 1,
"url": "https:\/\/hooks.example.com\/herd",
"events": [
"contact.created",
"contact.updated"
],
"is_active": true
}
headers = {
'Authorization': 'Bearer {YOUR_API_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('POST', url, headers=headers, json=payload)
response.json()
{
"data": {
"id": null,
"location_id": null,
"url": "https://example.test/webhooks/tP7QtxDt",
"events": [
"contact.created",
"message.received"
],
"is_active": true,
"last_delivery_at": null,
"created_at": null,
"updated_at": null,
"secret": "nHsIVY0AexDAbMktLudb8xsq6Ofw0OXkmU7NjPL1"
}
}
-
dataobject-
idstring -
location_idstring -
urlstring -
eventsstring[] -
is_activeboolean -
last_delivery_atstring -
created_atstring -
updated_atstring -
secretstring
-
{
"message": "Url no es una dirección web válida.",
"errors": {
"url": [
"Url no es una dirección web válida."
]
}
}
Every error shares the same shape — message and errors.
See Errors.
{
"message": "Events.0 no es una opción válida.",
"errors": {
"events.0": [
"Events.0 no es una opción válida."
]
}
}
Every error shares the same shape — message and errors.
See Errors.
Fetch a webhook endpoint
Returns one webhook endpoint by id: its URL, the events it is subscribed to and whether it is active. The signing secret is not returned here — it is shown once, when the endpoint is created. If you lost it, delete the endpoint and register it again; there is no way to read it back, which is the point.
GET
/api/webhook-endpoints/{webhookEndpoint_id}
To see what has actually been delivered, use
GET /api/webhook-endpoints/{id}/deliveries.
Path parameters
-
webhookEndpoint_idinteger requiredEndpoint ID.
Example:
6
curl --request GET \
--get "https://klozzo.com/api/webhook-endpoints/6" \
--header "Authorization: Bearer {YOUR_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://klozzo.com/api/webhook-endpoints/6"
);
const headers = {
"Authorization": "Bearer {YOUR_API_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://klozzo.com/api/webhook-endpoints/6';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_API_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json
url = 'https://klozzo.com/api/webhook-endpoints/6'
headers = {
'Authorization': 'Bearer {YOUR_API_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
{
"data": {
"id": null,
"location_id": null,
"url": "https://example.test/webhooks/Mh00hWJg",
"events": [
"contact.created",
"message.received"
],
"is_active": true,
"last_delivery_at": null,
"created_at": null,
"updated_at": null
}
}
-
dataobject-
idstring -
location_idstring -
urlstring -
eventsstring[] -
is_activeboolean -
last_delivery_atstring -
created_atstring -
updated_atstring
-
{
"message": "No query results for model."
}
Every error shares the same shape — message and errors.
See Errors.
Update a webhook endpoint
Updates a webhook endpoint by id, changing only the fields you send. To rotate the signing secret, delete and recreate.
PATCH
/api/webhook-endpoints/{webhookEndpoint_id}
Path parameters
-
webhookEndpoint_idinteger requiredEndpoint ID.
Example:
6
Body parameters
-
urlstringHTTPS URL (max 2048 chars).
Example:
https://hooks.example.com/herd -
eventsstring[]Subscribed event names.
Example:
["architecto"] -
is_activebooleanPause without deleting.
Example:
false
curl --request PATCH \
"https://klozzo.com/api/webhook-endpoints/6" \
--header "Authorization: Bearer {YOUR_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"url\": \"https:\\/\\/hooks.example.com\\/herd\",
\"events\": [
\"architecto\"
],
\"is_active\": false
}"
const url = new URL(
"https://klozzo.com/api/webhook-endpoints/6"
);
const headers = {
"Authorization": "Bearer {YOUR_API_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"url": "https:\/\/hooks.example.com\/herd",
"events": [
"architecto"
],
"is_active": false
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://klozzo.com/api/webhook-endpoints/6';
$response = $client->patch(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_API_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'url' => 'https://hooks.example.com/herd',
'events' => ['architecto'],
'is_active' => false,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json
url = 'https://klozzo.com/api/webhook-endpoints/6'
payload = {
"url": "https:\/\/hooks.example.com\/herd",
"events": [
"architecto"
],
"is_active": false
}
headers = {
'Authorization': 'Bearer {YOUR_API_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('PATCH', url, headers=headers, json=payload)
response.json()
{
"data": {
"id": null,
"location_id": null,
"url": "https://example.test/webhooks/USS1QLNW",
"events": [
"contact.created",
"message.received"
],
"is_active": true,
"last_delivery_at": null,
"created_at": null,
"updated_at": null
}
}
-
dataobject-
idstring -
location_idstring -
urlstring -
eventsstring[] -
is_activeboolean -
last_delivery_atstring -
created_atstring -
updated_atstring
-
Delete a webhook endpoint
Removes the endpoint and invalidates its signing secret. Historical
WebhookDelivery records remain for audit.
DELETE
/api/webhook-endpoints/{webhookEndpoint_id}
Path parameters
-
webhookEndpoint_idinteger requiredEndpoint ID.
Example:
6
curl --request DELETE \
"https://klozzo.com/api/webhook-endpoints/6" \
--header "Authorization: Bearer {YOUR_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://klozzo.com/api/webhook-endpoints/6"
);
const headers = {
"Authorization": "Bearer {YOUR_API_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://klozzo.com/api/webhook-endpoints/6';
$response = $client->delete(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_API_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json
url = 'https://klozzo.com/api/webhook-endpoints/6'
headers = {
'Authorization': 'Bearer {YOUR_API_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('DELETE', url, headers=headers)
response.json()
{
"message": "Webhook endpoint deleted."
}
-
messagestring
List delivery attempts for an endpoint
Returns recent delivery attempts (one row per HTTP call, including retries), newest first. Useful for debugging non-2xx responses from your endpoint.
GET
/api/webhook-endpoints/{webhookEndpoint_id}/deliveries
Path parameters
-
webhookEndpoint_idinteger requiredEndpoint ID.
Example:
6
Query parameters
-
per_pageintegerRows per page. Default 20, maximum 100. See Lists, paging and filters.
Example:
20
curl --request GET \
--get "https://klozzo.com/api/webhook-endpoints/6/deliveries?per_page=20" \
--header "Authorization: Bearer {YOUR_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"
const url = new URL(
"https://klozzo.com/api/webhook-endpoints/6/deliveries"
);
const params = {
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_API_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://klozzo.com/api/webhook-endpoints/6/deliveries';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_API_TOKEN}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'per_page' => '20',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json
url = 'https://klozzo.com/api/webhook-endpoints/6/deliveries'
params = {
'per_page': '20',
}
headers = {
'Authorization': 'Bearer {YOUR_API_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()
{
"data": [
{
"id": null,
"endpoint_id": 229,
"event_type": "contact.created",
"response_status": null,
"attempts": 0,
"delivered_at": null,
"created_at": null
},
{
"id": null,
"endpoint_id": 230,
"event_type": "contact.created",
"response_status": null,
"attempts": 0,
"delivered_at": null,
"created_at": null
}
],
"links": {
"first": "/?page=1",
"last": "/?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "/?page=1",
"label": "1",
"page": 1,
"active": true
},
{
"url": null,
"label": "Next »",
"page": null,
"active": false
}
],
"path": "/",
"per_page": 20,
"to": 2,
"total": 2
}
}
-
dataobject[]-
idstring -
endpoint_idinteger -
event_typestring -
response_statusstring -
attemptsinteger -
delivered_atstring -
created_atstring
-
-
linksobject-
firststring -
laststring -
prevstring -
nextstring
-
-
metaobject-
current_pageinteger -
frominteger -
last_pageinteger -
linksobject[]-
urlstring -
labelstring -
pagestring -
activeboolean
-
-
pathstring -
per_pageinteger -
tointeger -
totalinteger
-