Contacts
List, search, read, update and remove contacts, add them to campaigns and change many in one call.
Restore up to 1,000 soft-deleted contacts by id, the undo of bulk-delete
/v1/contacts/bulk-restorecontacts.bulk-restoreEach contact goes back into the campaign and segment it was deleted from, with its emails and fields unchanged. Nothing is charged and no enrichment re-runs. A restored contact is live again, so the planner of an active campaign can schedule its next email steps. LinkedIn steps the scheduler stopped while the contact was deleted (suppressed_contact_deleted) stay stopped. Any soft-deleted contact comes back, a lead the end client removed in a lead-list approval included, and that approval is not updated. succeeded lists the ids this call restored and restored counts them. Each other id is in failed with not_deleted (the contact is live, nothing changed; skipped counts these), not_found (missing or not in this workspace), or internal_error (retry that id). A retry is safe: an id an earlier call already restored comes back not_deleted. Requires campaigns edit, matching bulk-delete.
Parameters
400 workspace_required).Request body
application/json, optional.
Response 200
data is a ContactBulkRestoreResult.
not_deleted entries of Ken.Scraper.API.Canonical.ContactBulkRestoreResult.Failed.curl -X POST "https://api.ken.so/v1/contacts/bulk-restore" \
-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 '{
"ids": [
812
]
}'{
"success": true,
"data": {
"restored": 1,
"skipped": 1,
"succeeded": [
1
],
"failed": [
{
"id": 812,
"index": 1,
"error": {
"code": "string",
"message": "string"
}
}
]
}
}Add up to 1,000 contacts to a campaign
/v1/campaigns/{campaignId}/contactscontacts.createUses the existing campaign lead upsert, in batches of 100. Accepted and updated rows are succeeded. A later batch can fail without rolling back earlier rows; the upsert is safe to retry. customImageUrl sets the lead's own image (an empty string clears it): a malformed URL fails its row before anything is written, and a refused image (campaign images off for the workspace) fails its row with the contact's id, the contact itself saved. customVariables is an object of string values merged into the contact's custom variables (a null or empty value clears that key on an existing contact); a key new to the campaign joins its catalog with AI context off. A blank, unusable or reserved key, or more than 50 keys, fails its row before anything is written; a batch that would take the campaign past 50 custom variables fails every row in it. emailValidity (optional, safe for an email you already verified) qualifies a new contact on import in a campaign without AI qualification, spending one contact allowance; omitted keeps a stored verdict on an existing email. Requires WriteAccess. results has one item per row in request order: index, status (created, updated, skipped or failed), id when saved, and for a skipped or failed row a reason (duplicate, blocklisted, already_contacted, limit_reached, invalid_email, excluded, validation or other) and a message. A saved row has sendable, false when the contact will not send (added unqualified with no contact allowance left, or do-not-contact).
Parameters
400 workspace_required).Request body
application/json, optional.
Response 200
data is a ContactBulkResult.
contacts.create, in request order. Only that route fills it, so it is absent from the JSON of bulk-delete, bulk-pause and bulk-resume.curl -X POST "https://api.ken.so/v1/campaigns/812/contacts" \
-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 '{
"contacts": [
{
"email": "[email protected]",
"firstName": "string",
"lastName": "string",
"title": "string",
"linkedInUrl": "https://example.com",
"companyName": "string",
"companyDomain": "example.com",
"customImageUrl": "https://example.com",
"customVariables": {
"key": "string"
},
"emailValidity": "unknown"
}
]
}'{
"success": true,
"data": {
"succeeded": [
1
],
"failed": [
{
"id": 812,
"index": 1,
"error": {
"code": "string",
"message": "string"
}
}
],
"results": [
{
"index": 1,
"status": "string",
"id": 812,
"reason": "string",
"message": "string",
"sendable": true
}
]
}
}Ordered by id. Requires ReadAccess. Each contact on the page counts one row of the workspace's apiReadRows quota; past it, 429 quota_exceeded with Retry-After.
Parameters
400 workspace_required).Response 200
data is a list of ContactModel. Each item has these fields. The response also carries pagination.
paused (a member paused the lead), account_play, or a later value. Absent while it runs.fr-FR; a bare ISO 639-1 code for a language with no market pack). Omitted until Ken resolves one. PATCH sets it by hand and locks it.curl -X GET "https://api.ken.so/v1/contacts" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": [
{
"id": 90125,
"campaignId": 4821,
"segmentId": 1207,
"campaignListId": 3305,
"companyId": 22841,
"companyName": "Northwind Labs",
"companyEmailName": "Northwind",
"firstName": "Amanda",
"lastName": "Chen",
"email": "[email protected]",
"linkedInUrl": "https://www.linkedin.com/in/amanda-chen-northwind",
"title": "VP of Engineering",
"isQualified": true,
"doNotContact": false,
"isDecisionMaker": true,
"qualityScore": 86,
"qualityReasoning": "Leads a 40-person engineering team at a 120-person B2B SaaS company that is hiring engineers.",
"segmentationReasoning": "VP of Engineering, which matches the Engineering leaders segment.",
"customVariables": {
"open_roles": "12 engineering roles"
},
"emailsSent": 2,
"clicks": 0,
"replies": 1,
"unsubscribes": 0,
"bounces": 0,
"positiveReplies": 1,
"headline": "VP of Engineering at Northwind Labs",
"location": "Austin, Texas, United States",
"city": "Austin",
"state": "Texas",
"country": "United States",
"countryIso2": "US",
"companyLogo": "https://cdn.example.com/companies/22841/logo.png",
"linkedInUrlNameMismatch": false,
"segmentName": "Engineering leaders",
"emailValidity": "safe",
"emailFromKenPool": false,
"companyDomain": "northwind.example.com",
"companySize": "51-200",
"companyIndustry": "Software Development",
"companyLocation": "Austin, Texas, United States",
"companyEmployeeCount": 120,
"companyDescription": "Northwind Labs builds developer onboarding software for engineering teams.",
"companyFoundedYear": 2017,
"headquartersCity": "Austin",
"headquartersState": "Texas",
"headquartersCountry": "United States",
"seniorityLevel": "VP",
"function": "Engineering",
"yearsOfExperience": 14,
"outreachLanguage": "en-US",
"outreachLanguageSource": "country",
"outreachLanguageConfidence": 0.8,
"outreachLanguageLocked": false,
"phoneCountryAssumed": false,
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-10-13T16:22:05Z"
}
],
"pagination": {
"nextCursor": "eyJpZCI6ODE1fQ",
"hasMore": true,
"total": 1,
"isTotalCapped": true
}
}Search contacts in the current workspace
/v1/contacts/searchcontacts.searchSame filters as the list, plus more than one campaignIds value, lead filters groups, readyOnly, and contactIds. q is the free-text search. Ordered by id unless sort is set, in which case the cursor is an offset into that order. No total count. readyOnly requires exactly one campaign id. securityGateway and mailboxProvider filter on the contact's first Safe or Verified email and need security gateways on the workspace (400 otherwise). Requires ReadAccess. Pages count on apiReadRows like the list.
Parameters
400 workspace_required).Request body
application/json, optional.
proofpoint), none or pending; at most 100 values, OR'ed. Needs security gateways on the workspace.google_workspace), unknown or pending; at most 100 values, OR'ed. Needs security gateways on the workspace.POST /v1/leads.asc or desc. Empty means ascending.Response 200
data is a list of ContactModel. Each item has these fields. The response also carries pagination.
paused (a member paused the lead), account_play, or a later value. Absent while it runs.fr-FR; a bare ISO 639-1 code for a language with no market pack). Omitted until Ken resolves one. PATCH sets it by hand and locks it.curl -X POST "https://api.ken.so/v1/contacts/search" \
-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 '{
"campaignIds": [
812
],
"companyId": 812,
"segmentId": 812,
"email": "[email protected]",
"q": "string",
"isQualified": true,
"doNotContact": true,
"createdAfter": "2026-09-23T15:02:11Z",
"createdBefore": "2026-09-23T15:02:11Z",
"filters": [
{
"operator": 0,
"conditions": {
"field": "string",
"operator": 0,
"value": null,
"dataType": 0
},
"children": [
{}
]
}
],
"readyOnly": true,
"contactIds": [
812
],
"securityGateway": [
"string"
],
"mailboxProvider": [
"string"
],
"sort": "string",
"direction": "string",
"limit": 1,
"cursor": "eyJpZCI6ODE1fQ"
}'{
"success": true,
"data": [
{
"id": 90125,
"campaignId": 4821,
"segmentId": 1207,
"campaignListId": 3305,
"companyId": 22841,
"companyName": "Northwind Labs",
"companyEmailName": "Northwind",
"firstName": "Amanda",
"lastName": "Chen",
"email": "[email protected]",
"linkedInUrl": "https://www.linkedin.com/in/amanda-chen-northwind",
"title": "VP of Engineering",
"isQualified": true,
"doNotContact": false,
"isDecisionMaker": true,
"qualityScore": 86,
"qualityReasoning": "Leads a 40-person engineering team at a 120-person B2B SaaS company that is hiring engineers.",
"segmentationReasoning": "VP of Engineering, which matches the Engineering leaders segment.",
"customVariables": {
"open_roles": "12 engineering roles"
},
"emailsSent": 2,
"clicks": 0,
"replies": 1,
"unsubscribes": 0,
"bounces": 0,
"positiveReplies": 1,
"headline": "VP of Engineering at Northwind Labs",
"location": "Austin, Texas, United States",
"city": "Austin",
"state": "Texas",
"country": "United States",
"countryIso2": "US",
"companyLogo": "https://cdn.example.com/companies/22841/logo.png",
"linkedInUrlNameMismatch": false,
"segmentName": "Engineering leaders",
"emailValidity": "safe",
"emailFromKenPool": false,
"companyDomain": "northwind.example.com",
"companySize": "51-200",
"companyIndustry": "Software Development",
"companyLocation": "Austin, Texas, United States",
"companyEmployeeCount": 120,
"companyDescription": "Northwind Labs builds developer onboarding software for engineering teams.",
"companyFoundedYear": 2017,
"headquartersCity": "Austin",
"headquartersState": "Texas",
"headquartersCountry": "United States",
"seniorityLevel": "VP",
"function": "Engineering",
"yearsOfExperience": 14,
"outreachLanguage": "en-US",
"outreachLanguageSource": "country",
"outreachLanguageConfidence": 0.8,
"outreachLanguageLocked": false,
"phoneCountryAssumed": false,
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-10-13T16:22:05Z"
}
],
"pagination": {
"nextCursor": "eyJpZCI6ODE1fQ",
"hasMore": true,
"total": 1,
"isTotalCapped": true
}
}Return one contact in the current workspace
/v1/contacts/{contactId}contacts.getParameters
400 workspace_required).Response 200
data is a ContactModel.
paused (a member paused the lead), account_play, or a later value. Absent while it runs.fr-FR; a bare ISO 639-1 code for a language with no market pack). Omitted until Ken resolves one. PATCH sets it by hand and locks it.curl -X GET "https://api.ken.so/v1/contacts/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": 90125,
"campaignId": 4821,
"segmentId": 1207,
"campaignListId": 3305,
"companyId": 22841,
"companyName": "Northwind Labs",
"companyEmailName": "Northwind",
"firstName": "Amanda",
"lastName": "Chen",
"email": "[email protected]",
"linkedInUrl": "https://www.linkedin.com/in/amanda-chen-northwind",
"title": "VP of Engineering",
"isQualified": true,
"doNotContact": false,
"isDecisionMaker": true,
"qualityScore": 86,
"qualityReasoning": "Leads a 40-person engineering team at a 120-person B2B SaaS company that is hiring engineers.",
"segmentationReasoning": "VP of Engineering, which matches the Engineering leaders segment.",
"customVariables": {
"open_roles": "12 engineering roles"
},
"emailsSent": 2,
"clicks": 0,
"replies": 1,
"unsubscribes": 0,
"bounces": 0,
"positiveReplies": 1,
"headline": "VP of Engineering at Northwind Labs",
"location": "Austin, Texas, United States",
"city": "Austin",
"state": "Texas",
"country": "United States",
"countryIso2": "US",
"companyLogo": "https://cdn.example.com/companies/22841/logo.png",
"linkedInUrlNameMismatch": false,
"segmentName": "Engineering leaders",
"emailValidity": "safe",
"emailFromKenPool": false,
"companyDomain": "northwind.example.com",
"companySize": "51-200",
"companyIndustry": "Software Development",
"companyLocation": "Austin, Texas, United States",
"companyEmployeeCount": 120,
"companyDescription": "Northwind Labs builds developer onboarding software for engineering teams.",
"companyFoundedYear": 2017,
"headquartersCity": "Austin",
"headquartersState": "Texas",
"headquartersCountry": "United States",
"seniorityLevel": "VP",
"function": "Engineering",
"yearsOfExperience": 14,
"outreachLanguage": "en-US",
"outreachLanguageSource": "country",
"outreachLanguageConfidence": 0.8,
"outreachLanguageLocked": false,
"phoneCountryAssumed": false,
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-10-13T16:22:05Z"
}
}Absent fields stay unchanged. Null clears a string.
Requires WriteAccess, matching the legacy contact update. outreachLanguage (a locale whose language has a market pack or a country entry, such as fr-FR, es-MX or de) sets the language by hand: source manual, confidence 1, locked, so no import, enrichment or reply replaces it. Null clears and unlocks it. customVariables (an object of string or null values) merges into the contact's custom variables with the campaign lead upsert's rules: a string sets a key, null or an empty string removes it, keys not sent stay, and a new key joins the campaign's catalog. Absent leaves the bag unchanged; the object itself cannot be null. customImageUrl (a public https URL of at most 2048 characters) is the lead's own image, shown in emails as {{custom_image}}: Kenso downloads and hosts it. Empty or null clears it. It needs campaign images on the workspace; otherwise the update is a 400 validation_failed.
Parameters
400 workspace_required).Request body
application/json, required.
{{custom_image}}: a public https URL of at most 2048 characters that Kenso downloads and hosts. Empty or null clears it. Needs campaign images on the workspace.Response 200
data is a ContactModel.
paused (a member paused the lead), account_play, or a later value. Absent while it runs.fr-FR; a bare ISO 639-1 code for a language with no market pack). Omitted until Ken resolves one. PATCH sets it by hand and locks it.curl -X PATCH "https://api.ken.so/v1/contacts/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 '{
"firstName": "string",
"lastName": "string",
"title": "string",
"linkedInUrl": "https://example.com",
"location": "string",
"email": "[email protected]",
"isQualified": true,
"doNotContact": true,
"outreachLanguage": "string",
"customVariables": {
"key": "string"
},
"customImageUrl": "https://example.com"
}'{
"success": true,
"data": {
"id": 90125,
"campaignId": 4821,
"segmentId": 1207,
"campaignListId": 3305,
"companyId": 22841,
"companyName": "Northwind Labs",
"companyEmailName": "Northwind",
"firstName": "Amanda",
"lastName": "Chen",
"email": "[email protected]",
"linkedInUrl": "https://www.linkedin.com/in/amanda-chen-northwind",
"title": "VP of Engineering",
"isQualified": true,
"doNotContact": false,
"isDecisionMaker": true,
"qualityScore": 86,
"qualityReasoning": "Leads a 40-person engineering team at a 120-person B2B SaaS company that is hiring engineers.",
"segmentationReasoning": "VP of Engineering, which matches the Engineering leaders segment.",
"customVariables": {
"open_roles": "12 engineering roles"
},
"emailsSent": 2,
"clicks": 0,
"replies": 1,
"unsubscribes": 0,
"bounces": 0,
"positiveReplies": 1,
"headline": "VP of Engineering at Northwind Labs",
"location": "Austin, Texas, United States",
"city": "Austin",
"state": "Texas",
"country": "United States",
"countryIso2": "US",
"companyLogo": "https://cdn.example.com/companies/22841/logo.png",
"linkedInUrlNameMismatch": false,
"segmentName": "Engineering leaders",
"emailValidity": "safe",
"emailFromKenPool": false,
"companyDomain": "northwind.example.com",
"companySize": "51-200",
"companyIndustry": "Software Development",
"companyLocation": "Austin, Texas, United States",
"companyEmployeeCount": 120,
"companyDescription": "Northwind Labs builds developer onboarding software for engineering teams.",
"companyFoundedYear": 2017,
"headquartersCity": "Austin",
"headquartersState": "Texas",
"headquartersCountry": "United States",
"seniorityLevel": "VP",
"function": "Engineering",
"yearsOfExperience": 14,
"outreachLanguage": "en-US",
"outreachLanguageSource": "country",
"outreachLanguageConfidence": 0.8,
"outreachLanguageLocked": false,
"phoneCountryAssumed": false,
"createdAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-10-13T16:22:05Z"
}
}Requires WriteAccess, matching the legacy contact delete.
Parameters
400 workspace_required).Response 204
curl -X DELETE "https://api.ken.so/v1/contacts/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
Soft-delete up to 1,000 contacts by id
/v1/contacts/bulk-deletecontacts.bulk-deleteRequires ReadAccess, matching POST /v1/leads/bulk-delete. Ids outside the workspace are reported in failed and are not deleted.
Parameters
400 workspace_required).Request body
application/json, optional.
Response 200
data is a ContactBulkResult.
contacts.create, in request order. Only that route fills it, so it is absent from the JSON of bulk-delete, bulk-pause and bulk-resume.curl -X POST "https://api.ken.so/v1/contacts/bulk-delete" \
-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 '{
"ids": [
812
]
}'{
"success": true,
"data": {
"succeeded": [
1
],
"failed": [
{
"id": 812,
"index": 1,
"error": {
"code": "string",
"message": "string"
}
}
],
"results": [
{
"index": 1,
"status": "string",
"id": 812,
"reason": "string",
"message": "string",
"sendable": true
}
]
}
}Pause the campaign sequence of up to 1,000 contacts by id
/v1/contacts/bulk-pausecontacts.bulk-pauseNeeds the pause_leads feature on your workspace. Until it is on, calls answer 404.
Stops each contact's sequence in its campaign with the stop reason paused (sequenceStoppedAt and sequenceStopReason on the contact). This is not do-not-contact: the contact stays in other campaigns. Pending unsent steps of the paused contacts are cancelled. succeeded lists the ids that are paused after this call, a lead that was already paused included, so a retry is safe. Each other id is in failed with already_stopped (another stop reason holds it; the first stop wins), do_not_contact, not_found (not in this workspace, deleted, or not in a campaign), or internal_error (retry that id). Requires campaigns edit and launch (pausing stops live sends, as a campaign pause does) and the pause_leads feature; without it the route is 404.
Parameters
400 workspace_required).Request body
application/json, optional.
Response 200
data is a ContactBulkResult.
contacts.create, in request order. Only that route fills it, so it is absent from the JSON of bulk-delete, bulk-pause and bulk-resume.curl -X POST "https://api.ken.so/v1/contacts/bulk-pause" \
-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 '{
"ids": [
812
]
}'{
"success": true,
"data": {
"succeeded": [
1
],
"failed": [
{
"id": 812,
"index": 1,
"error": {
"code": "string",
"message": "string"
}
}
],
"results": [
{
"index": 1,
"status": "string",
"id": 812,
"reason": "string",
"message": "string",
"sendable": true
}
]
}
}Resume the campaign sequence of up to 1,000 paused contacts by id
/v1/contacts/bulk-resumecontacts.bulk-resumeClears the stop only where sequenceStopReason is paused, then asks the planner to plan each affected campaign now. A held LinkedIn step picks up within the hour. succeeded lists the ids this call resumed. Each other id is in failed with not_paused (no stop, or a stop with another reason, which stays) or not_found. Requires campaigns edit and launch, as bulk-pause. Not behind pause_leads: clearing a pause is always safe, so leads paused before the flag was turned off can still be resumed.
Parameters
400 workspace_required).Request body
application/json, optional.
Response 200
data is a ContactBulkResult.
contacts.create, in request order. Only that route fills it, so it is absent from the JSON of bulk-delete, bulk-pause and bulk-resume.curl -X POST "https://api.ken.so/v1/contacts/bulk-resume" \
-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 '{
"ids": [
812
]
}'{
"success": true,
"data": {
"succeeded": [
1
],
"failed": [
{
"id": 812,
"index": 1,
"error": {
"code": "string",
"message": "string"
}
}
],
"results": [
{
"index": 1,
"status": "string",
"id": 812,
"reason": "string",
"message": "string",
"sendable": true
}
]
}
}Update fields on up to 1,000 contacts in one call
/v1/contacts/bulk-updatecontacts.bulk-updateEach item is a contactId plus any fields PATCH /v1/contacts/{contactId} accepts, with the same semantics: absent fields stay unchanged, null clears a string. Items run one at a time in request order. A contact outside the workspace is not_found and is not written. A field error fails only that item. results is in request order; status is updated, not_found, validation_failed, or failed. The whole request is rejected, with nothing written, when items is empty, has more than 1,000 entries, has an entry that is not an object or lacks a positive contactId, or repeats a contactId. An item's customVariables merges as on the single update. Requires WriteAccess, matching the single update.
Parameters
400 workspace_required).Request body
application/json, required.
Response 200
data is a ContactBulkUpdateResult.
curl -X POST "https://api.ken.so/v1/contacts/bulk-update" \
-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 '{
"items": [
{
"firstName": "string",
"lastName": "string",
"title": "string",
"linkedInUrl": "https://example.com",
"location": "string",
"email": "[email protected]",
"isQualified": true,
"doNotContact": true,
"outreachLanguage": "string",
"customVariables": {
"key": "string"
},
"customImageUrl": "https://example.com",
"contactId": 812
}
]
}'{
"success": true,
"data": {
"updated": 1,
"failed": 1,
"results": [
{
"contactId": 812,
"status": "string",
"error": "string"
}
]
}
}List events for one contact
/v1/contacts/{contactId}/eventscontacts.eventsEvent ids are the stored event id, which is a string. Requires ReadAccess. A cursor is valid only with the same limit that issued it.
Parameters
400 workspace_required).Response 200
data is a list of ContactEventModel. Each item has these fields. The response also carries pagination.
video_event row is, as its VideoEventKindNames wire name (video_viewed, video_played, video_watched, video_liked or video_cta_clicked). Set only on video_event rows; omitted on every other row.curl -X GET "https://api.ken.so/v1/contacts/812/events" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": [
{
"id": "string",
"type": "string",
"occurredAt": "2026-09-23T15:02:11Z",
"campaignId": 812,
"kind": "string"
}
],
"pagination": {
"nextCursor": "eyJpZCI6ODE1fQ",
"hasMore": true,
"total": 1,
"isTotalCapped": true
}
}List every scraped website page of the contact's company
/v1/contacts/{contactId}/website-pagescontacts.list-website-pagesOne entry per distinct page with its markdown and scrape date. source is archive for pages copied from the Common Crawl archive (then scrapedAt is the archive capture date), live for pages Kenso scraped, and imported for content supplied in a CSV upload (then scrapedAt is the upload time). Ordered home, about, pricing, products, customer pages, careers, then the rest; newest first within a type. Pages without content are left out. At most 50 pages, not paginated. Requires ReadAccess.
Parameters
400 workspace_required).Response 200
data is a list of ContactWebsitePageModel. Each item has these fields. The response also carries pagination.
home, about, pricing, contact, blog, blog_articles, services, products, testimonials, case_studies, results, portfolio, gallery, reviews, privacy_policy, terms_of_service, careers, team, or other. Clients tolerate unknown values.archive (Common Crawl copy), live (scraped by Kenso), or imported (supplied in a CSV upload). Clients tolerate unknown values.curl -X GET "https://api.ken.so/v1/contacts/812/website-pages" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": [
{
"pageType": "string",
"url": "https://example.com",
"title": "string",
"markdown": "string",
"scrapedAt": "2026-09-23T15:02:11Z",
"source": "string"
}
],
"pagination": {
"nextCursor": "eyJpZCI6ODE1fQ",
"hasMore": true,
"total": 1,
"isTotalCapped": true
}
}