Kenso

Webhook endpoints

Endpoints Kenso posts events to: register them, read their signing secret, send a test and resend failed deliveries.

Webhooks and events8 endpointsKen-Version: 2026-11-02AuthenticationWorkspacesErrors

Each endpoint's health, lastDelivery and failedAttempts come from its latest 10 attempts.

Parameters

Name
In
Type
Required
Description
Limit
In: query
integer (int32)
optional
Cursor
In: query
string
optional
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Response 200

data is a list of WebhookEndpointModel. Each item has these fields. The response also carries pagination.

Field
Type
Description
id
string
url
string
events
array of string
description
string
isDisabled
boolean
createdAt
string (date-time)
app
string
zapier, make or n8n when the endpoint belongs to that app; null otherwise.
health
string
active, failing (the newest attempt failed) or disabled. Omitted, with lastDelivery and failedAttempts, when the delivery log could not be read.
lastDelivery
WebhookLastDeliveryModel
failedAttempts
integer (int32)
Failed attempts since the newest success among the latest 10 attempts; 0 unless failing.
campaignIds
array of integer (int64)
The campaign filter: the endpoint receives only events of these campaigns. Empty: every event. A filtered endpoint never receives an event that has no campaign.
classifications
array of string
The classification filter (snake_case reply.classified labels): the endpoint receives only events whose reply has one of them. Empty: every event. A filtered endpoint never receives an event without a reply classification. With Ken.Scraper.API.Canonical.WebhookEndpointModel.CampaignIds, both must match.
isBatched
boolean
The high-volume event types arrive as <type>.batch deliveries of up to 100 events ({eventType, eventId, timestamp, clientId, count, events}), never one by one.
Request
curl -X GET "https://api.ken.so/v1/webhook-endpoints" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
Response 200
{
  "success": true,
  "data": [
    {
      "id": "ep_2bKq8yZ0aB3cD4eF5gH6iJ7kL8m",
      "url": "https://hooks.example.com/kenso/replies",
      "events": [
        "reply.classified"
      ],
      "description": "Interested replies into our CRM",
      "isDisabled": false,
      "createdAt": "2026-09-23T15:02:11Z",
      "health": "active",
      "lastDelivery": {
        "occurredAt": "2026-10-13T16:22:41Z",
        "status": "success",
        "responseStatusCode": 200,
        "eventType": "reply.classified"
      },
      "failedAttempts": 0,
      "campaignIds": [
        4821
      ],
      "classifications": [
        "interested"
      ],
      "isBatched": false
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6ODE1fQ",
    "hasMore": true,
    "total": 1,
    "isTotalCapped": true
  }
}

Register a webhook endpoint

POST/v1/webhook-endpointswebhook-endpoints.create

Try it on developer.ken.so

Requires the integrations permission (admins by default). url must be https outside Development. events is a non-empty set of supported event types. app (zapier, make or n8n) tags the endpoint; omitted, it is taken from the URL host. campaignIds (workspace campaigns; another workspace's id is not_found) and classifications (snake_case labels) filter deliveries; both together must both match. A filter holds at most 10 campaigns, 10 classifications, or campaigns times classifications up to 10. isBatched delivers the high-volume types as batches; it needs an events list and is refused while batching is off.

Parameters

Name
In
Type
Required
Description
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Request body

application/json, optional.

Field
Type
Required
Description
url
string
optional
events
array of string
optional
description
string
optional
app
string
optional
zapier, make or n8n. Omitted: taken from the URL host when it is a known catch-hook host.
campaignIds
array of integer (int64)
optional
Deliver only events of these workspace campaigns. Omitted or empty: every campaign.
classifications
array of string
optional
Deliver only events with these reply classifications (snake_case, as in reply.classified). Omitted or empty: every one.
isBatched
boolean
optional
Receive the high-volume event types as batches. Default false.

Response 201

data is a WebhookEndpointModel.

Field
Type
Description
id
string
url
string
events
array of string
description
string
isDisabled
boolean
createdAt
string (date-time)
app
string
zapier, make or n8n when the endpoint belongs to that app; null otherwise.
health
string
active, failing (the newest attempt failed) or disabled. Omitted, with lastDelivery and failedAttempts, when the delivery log could not be read.
lastDelivery
WebhookLastDeliveryModel
failedAttempts
integer (int32)
Failed attempts since the newest success among the latest 10 attempts; 0 unless failing.
campaignIds
array of integer (int64)
The campaign filter: the endpoint receives only events of these campaigns. Empty: every event. A filtered endpoint never receives an event that has no campaign.
classifications
array of string
The classification filter (snake_case reply.classified labels): the endpoint receives only events whose reply has one of them. Empty: every event. A filtered endpoint never receives an event without a reply classification. With Ken.Scraper.API.Canonical.WebhookEndpointModel.CampaignIds, both must match.
isBatched
boolean
The high-volume event types arrive as <type>.batch deliveries of up to 100 events ({eventType, eventId, timestamp, clientId, count, events}), never one by one.
Request
curl -X POST "https://api.ken.so/v1/webhook-endpoints" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://hooks.example.com/kenso/replies",
  "events": [
    "reply.classified"
  ],
  "description": "Interested replies into our CRM",
  "campaignIds": [
    4821
  ],
  "classifications": [
    "interested"
  ],
  "isBatched": false
}'
Response 201
{
  "success": true,
  "data": {
    "id": "ep_2bKq8yZ0aB3cD4eF5gH6iJ7kL8m",
    "url": "https://hooks.example.com/kenso/replies",
    "events": [
      "reply.classified"
    ],
    "description": "Interested replies into our CRM",
    "isDisabled": false,
    "createdAt": "2026-09-23T15:02:11Z",
    "health": "active",
    "lastDelivery": {
      "occurredAt": "2026-10-13T16:22:41Z",
      "status": "success",
      "responseStatusCode": 200,
      "eventType": "reply.classified"
    },
    "failedAttempts": 0,
    "campaignIds": [
      4821
    ],
    "classifications": [
      "interested"
    ],
    "isBatched": false
  }
}

Get one webhook endpoint

GET/v1/webhook-endpoints/{webhookEndpointId}webhook-endpoints.get

Try it on developer.ken.so

health, lastDelivery and failedAttempts come from the endpoint's latest 10 attempts.

Parameters

Name
In
Type
Required
Description
webhookEndpointId
In: path
string
required
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Response 200

data is a WebhookEndpointModel.

Field
Type
Description
id
string
url
string
events
array of string
description
string
isDisabled
boolean
createdAt
string (date-time)
app
string
zapier, make or n8n when the endpoint belongs to that app; null otherwise.
health
string
active, failing (the newest attempt failed) or disabled. Omitted, with lastDelivery and failedAttempts, when the delivery log could not be read.
lastDelivery
WebhookLastDeliveryModel
failedAttempts
integer (int32)
Failed attempts since the newest success among the latest 10 attempts; 0 unless failing.
campaignIds
array of integer (int64)
The campaign filter: the endpoint receives only events of these campaigns. Empty: every event. A filtered endpoint never receives an event that has no campaign.
classifications
array of string
The classification filter (snake_case reply.classified labels): the endpoint receives only events whose reply has one of them. Empty: every event. A filtered endpoint never receives an event without a reply classification. With Ken.Scraper.API.Canonical.WebhookEndpointModel.CampaignIds, both must match.
isBatched
boolean
The high-volume event types arrive as <type>.batch deliveries of up to 100 events ({eventType, eventId, timestamp, clientId, count, events}), never one by one.
Request
curl -X GET "https://api.ken.so/v1/webhook-endpoints/string" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
Response 200
{
  "success": true,
  "data": {
    "id": "ep_2bKq8yZ0aB3cD4eF5gH6iJ7kL8m",
    "url": "https://hooks.example.com/kenso/replies",
    "events": [
      "reply.classified"
    ],
    "description": "Interested replies into our CRM",
    "isDisabled": false,
    "createdAt": "2026-09-23T15:02:11Z",
    "health": "active",
    "lastDelivery": {
      "occurredAt": "2026-10-13T16:22:41Z",
      "status": "success",
      "responseStatusCode": 200,
      "eventType": "reply.classified"
    },
    "failedAttempts": 0,
    "campaignIds": [
      4821
    ],
    "classifications": [
      "interested"
    ],
    "isBatched": false
  }
}

Update a webhook endpoint

PATCH/v1/webhook-endpoints/{webhookEndpointId}webhook-endpoints.update

Try it on developer.ken.so

Requires the integrations permission (admins by default). Omitted fields stay unchanged. isDisabled pauses or resumes delivery. app sets the app tag; an empty string clears it. campaignIds and classifications replace that filter (empty clears it); the one omitted keeps its value. isBatched turns batch delivery on or off.

Parameters

Name
In
Type
Required
Description
webhookEndpointId
In: path
string
required
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Request body

application/json, optional.

Field
Type
Required
Description
url
string
optional
events
array of string
optional
description
string
optional
isDisabled
boolean
optional
app
string
optional
zapier, make or n8n. Omitted: unchanged. An empty string clears the tag.
campaignIds
array of integer (int64)
optional
Campaign filter. Omitted: unchanged. Empty: every campaign.
classifications
array of string
optional
Classification filter (snake_case). Omitted: unchanged. Empty: every classification.
isBatched
boolean
optional
Batch delivery of the high-volume types. Omitted: unchanged.

Response 200

data is a WebhookEndpointModel.

Field
Type
Description
id
string
url
string
events
array of string
description
string
isDisabled
boolean
createdAt
string (date-time)
app
string
zapier, make or n8n when the endpoint belongs to that app; null otherwise.
health
string
active, failing (the newest attempt failed) or disabled. Omitted, with lastDelivery and failedAttempts, when the delivery log could not be read.
lastDelivery
WebhookLastDeliveryModel
failedAttempts
integer (int32)
Failed attempts since the newest success among the latest 10 attempts; 0 unless failing.
campaignIds
array of integer (int64)
The campaign filter: the endpoint receives only events of these campaigns. Empty: every event. A filtered endpoint never receives an event that has no campaign.
classifications
array of string
The classification filter (snake_case reply.classified labels): the endpoint receives only events whose reply has one of them. Empty: every event. A filtered endpoint never receives an event without a reply classification. With Ken.Scraper.API.Canonical.WebhookEndpointModel.CampaignIds, both must match.
isBatched
boolean
The high-volume event types arrive as <type>.batch deliveries of up to 100 events ({eventType, eventId, timestamp, clientId, count, events}), never one by one.
Request
curl -X PATCH "https://api.ken.so/v1/webhook-endpoints/string" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com",
  "events": [
    "string"
  ],
  "description": "string",
  "isDisabled": true,
  "app": "string",
  "campaignIds": [
    812
  ],
  "classifications": [
    "string"
  ],
  "isBatched": true
}'
Response 200
{
  "success": true,
  "data": {
    "id": "ep_2bKq8yZ0aB3cD4eF5gH6iJ7kL8m",
    "url": "https://hooks.example.com/kenso/replies",
    "events": [
      "reply.classified"
    ],
    "description": "Interested replies into our CRM",
    "isDisabled": false,
    "createdAt": "2026-09-23T15:02:11Z",
    "health": "active",
    "lastDelivery": {
      "occurredAt": "2026-10-13T16:22:41Z",
      "status": "success",
      "responseStatusCode": 200,
      "eventType": "reply.classified"
    },
    "failedAttempts": 0,
    "campaignIds": [
      4821
    ],
    "classifications": [
      "interested"
    ],
    "isBatched": false
  }
}

Delete a webhook endpoint

DELETE/v1/webhook-endpoints/{webhookEndpointId}webhook-endpoints.delete

Try it on developer.ken.so

Parameters

Name
In
Type
Required
Description
webhookEndpointId
In: path
string
required
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Response 204

Request
curl -X DELETE "https://api.ken.so/v1/webhook-endpoints/string" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
Response 204
HTTP/1.1 204 No Content

Get the endpoint signing secret

GET/v1/webhook-endpoints/{webhookEndpointId}/signing-secretwebhook-endpoints.get-signing-secret

Try it on developer.ken.so

Requires the integrations permission (admins by default). Treat secret as a credential.

Parameters

Name
In
Type
Required
Description
webhookEndpointId
In: path
string
required
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Response 200

data is a WebhookSigningSecretModel.

Field
Type
Description
secret
string
Request
curl -X GET "https://api.ken.so/v1/webhook-endpoints/string/signing-secret" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
Response 200
{
  "success": true,
  "data": {
    "secret": "string"
  }
}

Resend failed deliveries since a time

POST/v1/webhook-endpoints/{webhookEndpointId}/recoverwebhook-endpoints.recover

Try it on developer.ken.so

Resends every delivery to this endpoint that failed in the window and never succeeded. since is required and at most 14 days ago; until defaults to now. Svix runs the resends in the background, so the response is 202 with the window. Counts as 10 resends against the workspace's resend limit.

Parameters

Name
In
Type
Required
Description
webhookEndpointId
In: path
string
required
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Request body

application/json, optional.

Field
Type
Required
Description
since
string (date-time)
optional
Required. Start of the window (ISO 8601, UTC), at most 14 days ago.
until
string (date-time)
optional
End of the window (ISO 8601, UTC). Default: now.

Response 202

data is a WebhookRecoverModel.

Field
Type
Description
since
string (date-time)
until
string (date-time)
Request
curl -X POST "https://api.ken.so/v1/webhook-endpoints/string/recover" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "since": "2026-09-23T15:02:11Z",
  "until": "2026-09-23T15:02:11Z"
}'
Response 202
{
  "success": true,
  "data": {
    "since": "2026-09-23T15:02:11Z",
    "until": "2026-09-23T15:02:11Z"
  }
}

Send a test event to one endpoint

POST/v1/webhook-endpoints/{webhookEndpointId}/testwebhook-endpoints.test

Try it on developer.ken.so

Requires the integrations feature. Sends the example payload of eventType to this endpoint only and waits up to 5 seconds for the first attempt. eventType is any event type available to the workspace, whether or not the endpoint receives it or filters by campaign or classification; it defaults to the first event the endpoint receives (reply.received when it receives every event). A batched endpoint gets a high-volume type's <type>.batch example, and eventType in the response says so. A type the workspace cannot use is validation_failed. A disabled endpoint is invalid_state.

Parameters

Name
In
Type
Required
Description
webhookEndpointId
In: path
string
required
Ken-Version
In: header
string, one of: 2026-11-02, 1.1
required
The API version: a dated version (YYYY-MM-DD), or 1.1, another name for the first dated version. Without it the request uses your API key's pinned version; an unpinned key reaches the legacy shape of the same path. 1.0 selects the legacy shape explicitly.
X-Ken-Workspace-Id
In: header
integer (int64)
optional
Workspace to act in. Required when your credential can reach more than one workspace (otherwise 400 workspace_required).

Request body

application/json, optional.

Field
Type
Required
Description
eventType
string
optional
Event type to send: any type available to the workspace, whether or not the endpoint receives it. Default: the first event the endpoint receives (reply.received for every event).

Response 200

data is a WebhookEndpointTestModel.

Field
Type
Description
messageId
string
The Svix message id (msg_) of the test delivery.
eventType
string
attempt
WebhookEndpointTestAttemptModel
Request
curl -X POST "https://api.ken.so/v1/webhook-endpoints/string/test" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "eventType": "string"
}'
Response 200
{
  "success": true,
  "data": {
    "messageId": "msg_ZW1haWw6NDAyMjg0LjJAZXhhbXBsZS5jb20",
    "eventType": "string",
    "attempt": {
      "status": "string",
      "responseStatusCode": 1,
      "occurredAt": "2026-09-23T15:02:11Z"
    }
  }
}