Scraping
Scrape, map, crawl and search the web, and extract structured data from pages.
A page served from Kenso's archive is free and counts one unit of the workspace's webArchiveReads quota ; past it, 429 quota_exceeded with Retry-After. A call through a customer's own MCP connection (X-Ken-Mcp-Connection: customer) first counts one webReadCalls unit.
Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 200
data is a object.
curl -X POST "https://api.ken.so/v1/scraping/scrape" \
-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": null
}A call through a customer's own MCP connection (X-Ken-Mcp-Connection: customer) counts one webReadCalls unit; past it, 429 quota_exceeded with Retry-After.
Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 200
data is a object.
curl -X POST "https://api.ken.so/v1/scraping/map" \
-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": null
}Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 200
data is a object.
curl -X POST "https://api.ken.so/v1/scraping/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 '{}'{
"success": true,
"data": null
}Start a crawl and return a job
/v1/scraping/crawlsscraping.create-crawlRequires ReadAccess. The response is 202 with a crawl job. Poll GET /v1/jobs/{jobId}?type=crawl. Cancel with POST /v1/jobs/{jobId}/cancel?type=crawl. SSRF rejection stays in the Firecrawl service. The body needs a limit of 1 to 1,000 pages. When the job cannot be recorded, the started crawl is stopped and the answer is 503 service_unavailable.
Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 202
data is a JobModel.
inbox_import job. Passwords are never returned.contact_import job with target people: each row created a person, updated (matched) one, or was skipped (no email, LinkedIn URL, or name with a business company domain, or intake refused it).contact_import job skipped, by reason. The duplicate counts name the rule that dropped the row: a contact already in this campaign, a contact in another campaign of the workspace (the campaign dedups against other campaigns), an earlier row of the same import, or the campaign's recently-emailed window.curl -X POST "https://api.ken.so/v1/scraping/crawls" \
-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,
"type": "string",
"status": "string",
"progress": {
"completed": 1,
"total": 1
},
"resource": {
"type": "string",
"id": 812
},
"createdAt": "2026-09-23T15:02:11Z",
"downloadUrl": "https://example.com",
"error": {
"code": "string",
"message": "string"
},
"result": null,
"domainsListed": 1,
"excludedLibraryContacts": 1,
"inboxImport": {
"connectedCount": 1,
"failedCount": 1,
"skippedCount": 1,
"startedAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z",
"completedAt": "2026-09-23T15:02:11Z",
"rows": [
{
"index": 1,
"email": "[email protected]",
"status": "string",
"inboxId": 812,
"errorCode": "string",
"message": "string"
}
]
},
"personImport": {
"source": "string",
"createdCount": 1,
"updatedCount": 1,
"skippedCount": 1,
"startedAt": "2026-09-23T15:02:11Z",
"completedAt": "2026-09-23T15:02:11Z"
},
"skipped": {
"duplicateInCampaign": 1,
"duplicateInOtherCampaign": 1,
"duplicateInSource": 1,
"alreadyContacted": 1,
"blocklist": 1,
"failedValidation": 1,
"salesNavigatorProfileUnresolved": 1,
"other": 1,
"missingKey": 1,
"invalidEmail": 1,
"noMx": 1,
"catchAll": 1,
"personalEmail": 1,
"roleAddress": 1,
"companyContacted": 1,
"companyCap": 1
}
}
}Start an extraction and return a job
/v1/scraping/extractionsscraping.create-extractionRequires ReadAccess. The response is 202 with an extraction job. Poll GET /v1/jobs/{jobId}?type=extraction. Extraction cannot be canceled.
Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 202
data is a JobModel.
inbox_import job. Passwords are never returned.contact_import job with target people: each row created a person, updated (matched) one, or was skipped (no email, LinkedIn URL, or name with a business company domain, or intake refused it).contact_import job skipped, by reason. The duplicate counts name the rule that dropped the row: a contact already in this campaign, a contact in another campaign of the workspace (the campaign dedups against other campaigns), an earlier row of the same import, or the campaign's recently-emailed window.curl -X POST "https://api.ken.so/v1/scraping/extractions" \
-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,
"type": "string",
"status": "string",
"progress": {
"completed": 1,
"total": 1
},
"resource": {
"type": "string",
"id": 812
},
"createdAt": "2026-09-23T15:02:11Z",
"downloadUrl": "https://example.com",
"error": {
"code": "string",
"message": "string"
},
"result": null,
"domainsListed": 1,
"excludedLibraryContacts": 1,
"inboxImport": {
"connectedCount": 1,
"failedCount": 1,
"skippedCount": 1,
"startedAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z",
"completedAt": "2026-09-23T15:02:11Z",
"rows": [
{
"index": 1,
"email": "[email protected]",
"status": "string",
"inboxId": 812,
"errorCode": "string",
"message": "string"
}
]
},
"personImport": {
"source": "string",
"createdCount": 1,
"updatedCount": 1,
"skippedCount": 1,
"startedAt": "2026-09-23T15:02:11Z",
"completedAt": "2026-09-23T15:02:11Z"
},
"skipped": {
"duplicateInCampaign": 1,
"duplicateInOtherCampaign": 1,
"duplicateInSource": 1,
"alreadyContacted": 1,
"blocklist": 1,
"failedValidation": 1,
"salesNavigatorProfileUnresolved": 1,
"other": 1,
"missingKey": 1,
"invalidEmail": 1,
"noMx": 1,
"catchAll": 1,
"personalEmail": 1,
"roleAddress": 1,
"companyContacted": 1,
"companyCap": 1
}
}
}Start a batch scrape and return a job
/v1/scraping/batch-scrapesscraping.create-batch-scrapeRequires ReadAccess. The response is 202 with a batch_scrape job. Poll GET /v1/jobs/{jobId}?type=batch_scrape. Cancel with POST /v1/jobs/{jobId}/cancel?type=batch_scrape.
Parameters
400 workspace_required).Request body
application/json, optional: object.
Response 202
data is a JobModel.
inbox_import job. Passwords are never returned.contact_import job with target people: each row created a person, updated (matched) one, or was skipped (no email, LinkedIn URL, or name with a business company domain, or intake refused it).contact_import job skipped, by reason. The duplicate counts name the rule that dropped the row: a contact already in this campaign, a contact in another campaign of the workspace (the campaign dedups against other campaigns), an earlier row of the same import, or the campaign's recently-emailed window.curl -X POST "https://api.ken.so/v1/scraping/batch-scrapes" \
-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,
"type": "string",
"status": "string",
"progress": {
"completed": 1,
"total": 1
},
"resource": {
"type": "string",
"id": 812
},
"createdAt": "2026-09-23T15:02:11Z",
"downloadUrl": "https://example.com",
"error": {
"code": "string",
"message": "string"
},
"result": null,
"domainsListed": 1,
"excludedLibraryContacts": 1,
"inboxImport": {
"connectedCount": 1,
"failedCount": 1,
"skippedCount": 1,
"startedAt": "2026-09-23T15:02:11Z",
"updatedAt": "2026-09-23T15:02:11Z",
"completedAt": "2026-09-23T15:02:11Z",
"rows": [
{
"index": 1,
"email": "[email protected]",
"status": "string",
"inboxId": 812,
"errorCode": "string",
"message": "string"
}
]
},
"personImport": {
"source": "string",
"createdCount": 1,
"updatedCount": 1,
"skippedCount": 1,
"startedAt": "2026-09-23T15:02:11Z",
"completedAt": "2026-09-23T15:02:11Z"
},
"skipped": {
"duplicateInCampaign": 1,
"duplicateInOtherCampaign": 1,
"duplicateInSource": 1,
"alreadyContacted": 1,
"blocklist": 1,
"failedValidation": 1,
"salesNavigatorProfileUnresolved": 1,
"other": 1,
"missingKey": 1,
"invalidEmail": 1,
"noMx": 1,
"catchAll": 1,
"personalEmail": 1,
"roleAddress": 1,
"companyContacted": 1,
"companyCap": 1
}
}
}