Triggers
Rules that act when a signal happens: create, preview, edit, archive and read their stats.
Preview the companies a trigger would act on, with pass counts per gate step and an estimated credit cost
/v1/triggers/previewtriggers.previewRuns the definition's parameters against live data without saving anything: nothing fires and nothing is charged. signalType is fundraising, open_roles or company_headcount_growth; any other signal returns 400 validation_failed with details[0].codepreview_not_supported. parameters is a JSON object with the same keys a trigger stores. limit 1 to 25 companies (default 25), cursor pagination through pagination.nextCursor. Every page has companies (sample rows), total (the source's count across pages, null for open_roles), steps (name, count and description of each gate step on this page, in order, ending with max_contacts_per_company, the most people the page can import) and estimatedCredits (isEstimate true, leads, credits, totalMillicredits, lines, and basis, which says how it was computed: those people at the leads rate of credit-estimates.create). Free: never uses the export allowance.
Parameters
400 workspace_required).Request body
application/json, optional.
fundraising, open_roles or company_headcount_growth.pagination.nextCursor of the previous page.Response 200
data is a object.
curl -X POST "https://api.ken.so/v1/triggers/preview" \
-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 '{
"signalType": "string",
"parameters": null,
"limit": 1,
"cursor": "eyJpZCI6ODE1fQ"
}'{
"success": true,
"data": null
}Test-fire a saved trigger against a sample signal
/v1/triggers/{triggerId}/test-firetriggers.test-fireEvaluates one sample signal of the trigger's own type, the way an arriving signal is evaluated, and says whether it would fire and why. Read-only: no signal is queued, no cooldown is taken, no firing is written, no window counter changes, and nothing is sent or charged. Recent signals are not replayed; the sample is the only input. contactId is required, campaignId feeds the audience filter, payload is the signal's JSON object (for example clickedUrl for link_clicked, classification for reply_received), occurredAt defaults to now. checks run in pipeline order (status, audience_filter, parameters, cooldown), every one runs, and rejectedBy names the first that failed; status fails for a paused or archived trigger and for one whose campaign is deleted. A firing can still be suppressed later (do not contact, blocklist, frequency cap). A contact or campaign outside the workspace is 400; signals that only a scheduled sweep produces return 400 with details[0].codetest_fire_not_supported.
Parameters
400 workspace_required).Request body
application/json, optional.
{"clickedUrl":"https://..."}.Response 200
data is a TriggerTestFireModel.
trigger_test_fire.active, paused or archived.status, audience_filter, parameters, cooldown. Every check runs.curl -X POST "https://api.ken.so/v1/triggers/812/test-fire" \
-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 '{
"contactId": 812,
"campaignId": 812,
"payload": null,
"occurredAt": "2026-09-23T15:02:11Z"
}'{
"success": true,
"data": {
"object": "string",
"triggerId": 812,
"signalType": "string",
"status": "string",
"shouldFire": true,
"rejectedBy": "string",
"checks": [
{
"name": "string",
"passed": true,
"message": "string"
}
],
"evidence": null,
"scheduledFor": "2026-09-23T15:02:11Z"
}
}List trigger definitions in the current workspace
/v1/triggerstriggers.listParameters
400 workspace_required).Response 200
data is a list of TriggerModel. Each item has these fields. The response also carries pagination.
curl -X GET "https://api.ken.so/v1/triggers" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": [
{
"id": 812,
"campaignId": 812,
"stagingCampaignId": 812,
"signalType": "string",
"tier": "string",
"parameters": "string",
"audienceFilter": "string",
"cooldownMinutes": 1,
"maxAgeMinutes": 1,
"priority": 1,
"stopSourceSequence": true,
"status": "string",
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z"
}
],
"pagination": {
"nextCursor": "eyJpZCI6ODE1fQ",
"hasMore": true,
"total": 1,
"isTotalCapped": true
}
}Requires Campaigns edit access (owners, admins and editors by default). The campaign must belong to the workspace and be in trigger mode, or be a Batch campaign when switchCampaignToTrigger is true (the switch and the create are one transaction); the LinkedIn signal types (linkedin_post_engagement, linkedin_profile_view) take a regular campaign instead and need the workspace's linkedin_signals flag.
Parameters
400 workspace_required).Request body
application/json, optional.
Response 201
data is a TriggerModel.
curl -X POST "https://api.ken.so/v1/triggers" \
-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 '{
"campaignId": 812,
"signalType": "string",
"tier": "string",
"parameters": "string",
"audienceFilter": "string",
"cooldownMinutes": 1,
"maxAgeMinutes": 1,
"priority": 1,
"stopSourceSequence": true,
"switchCampaignToTrigger": true
}'{
"success": true,
"data": {
"id": 812,
"campaignId": 812,
"stagingCampaignId": 812,
"signalType": "string",
"tier": "string",
"parameters": "string",
"audienceFilter": "string",
"cooldownMinutes": 1,
"maxAgeMinutes": 1,
"priority": 1,
"stopSourceSequence": true,
"status": "string",
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z"
}
}Parameters
400 workspace_required).Response 200
data is a TriggerModel.
curl -X GET "https://api.ken.so/v1/triggers/812" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": {
"id": 812,
"campaignId": 812,
"stagingCampaignId": 812,
"signalType": "string",
"tier": "string",
"parameters": "string",
"audienceFilter": "string",
"cooldownMinutes": 1,
"maxAgeMinutes": 1,
"priority": 1,
"stopSourceSequence": true,
"status": "string",
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z"
}
}Requires Campaigns edit access (owners, admins and editors by default). Omitted fields stay unchanged. audienceFilter: null clears the filter.
Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 200
data is a TriggerModel.
curl -X PATCH "https://api.ken.so/v1/triggers/812" \
-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 '{}'{
"success": true,
"data": {
"id": 812,
"campaignId": 812,
"stagingCampaignId": 812,
"signalType": "string",
"tier": "string",
"parameters": "string",
"audienceFilter": "string",
"cooldownMinutes": 1,
"maxAgeMinutes": 1,
"priority": 1,
"stopSourceSequence": true,
"status": "string",
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z"
}
}Parameters
400 workspace_required).Response 204
curl -X DELETE "https://api.ken.so/v1/triggers/812" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
HTTP/1.1 204 No Content
Firing stats for one trigger
/v1/triggers/{triggerId}/statstriggers.get-statsParameters
400 workspace_required).Response 200
data is a TriggerStatsModel.
curl -X GET "https://api.ken.so/v1/triggers/812/stats" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": {
"fired": 1,
"exported": 1,
"suppressed": 1,
"suppressionBreakdown": {
"key": 1
},
"lastFiredAt": "2026-09-23T15:02:11Z"
}
}LinkedIn engagements a LinkedIn signal trigger stored
/v1/triggers/{triggerId}/linkedin-engagementstriggers.list-linkedin-engagementsNeeds the linkedin_signals feature on your workspace. Until it is on, calls answer 404.
Newest first. status filters to new, imported, offered or skipped. Each item names the engager (actor), the post and comment when there is one, and for imported the person's contact in the campaign; skipReason says why an item was skipped. Items also carry the reaction type, the comment and parent comment ids, the post text, Jev's intent and reason, and ownPost. A trigger of another signal type returns an empty list. 404 while the workspace's linkedin_signals flag is off.
Parameters
pagination.nextCursor.new, imported, offered or skipped.400 workspace_required).Response 200
data is a list of LinkedInEngagementModel. Each item has these fields. The response also carries pagination.
curl -X GET "https://api.ken.so/v1/triggers/812/linkedin-engagements" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": [
{
"id": 812,
"kind": "string",
"postUrl": "https://example.com",
"actor": {
"name": "string",
"headline": "string",
"profileUrl": "https://example.com"
},
"commentText": "string",
"reactionType": "string",
"commentId": "string",
"parentCommentId": "string",
"postText": "string",
"intent": "string",
"intentReason": "string",
"ownPost": true,
"occurredAt": "2026-09-23T15:02:11Z",
"firstSeenAt": "2026-09-23T15:02:11Z",
"status": "string",
"skipReason": "string",
"contactId": 812
}
],
"pagination": {
"nextCursor": "eyJpZCI6ODE1fQ",
"hasMore": true,
"total": 1,
"isTotalCapped": true
}
}