Kenso

Jobs

Long-running work such as imports, exports, health checks and crawls: list the jobs of one type, read one and cancel it.

Contacts and lists3 endpointsKen-Version: 2026-11-02AuthenticationWorkspacesErrors

Requires type because ids collide across sources. Scraping types are crawl, extraction, and batch_scrape. Optional status is a comma-separated OR filter. A knowledge_export list holds only the caller's own exports. A migration list is newest first (the cursor is an upper bound); every other type lists oldest first. Read-only. Each type also needs what its own routes need: crawl, extraction and batch_scrape Search view, domain_health Delivery view, contact_import, lead_scoring and enrichment Campaigns view, contact_export Campaigns view and the Export feature, knowledge_export Knowledge view, and migration workspace Admin (the Integrations feature). Without it the call is 403 permission_denied.

Parameters

Name
In
Type
Required
Description
Type
In: query
string
optional
contact_import or domain_health.
Status
In: query
string
optional
Comma-separated statuses: queued, running, succeeded, failed, canceled.
Limit
In: query
integer (int32)
optional
Page size. Default 50, maximum 200.
Cursor
In: query
string
optional
Opaque cursor returned as pagination.nextCursor.
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 JobModel. Each item has these fields. The response also carries pagination.

Field
Type
Description
id
integer (int64)
type
string
status
string
progress
JobProgressModel
resource
JobResourceModel
createdAt
string (date-time)
downloadUrl
string
error
JobErrorModel
result
object
Upstream payload for a scraping job get. Omitted for other types and for lists.
domainsListed
integer (int32)
Listed-domain count stored by a completed domain health sweep. Omitted until that count exists.
excludedLibraryContacts
integer (int32)
Contacts from a Kenso library list a contact export left out (they are never exported), including 0. Only on contact_export jobs of kind contacts, campaign and advanced; omitted otherwise.
inboxImport
InboxImportJobModel
Counts and per-row results of an inbox_import job. Passwords are never returned.
personImport
PersonImportJobModel
Counts of a 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).
skipped
ContactImportSkipsModel
Rows a campaign 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.
Request
curl -X GET "https://api.ken.so/v1/jobs" \
  -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": 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
      }
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6ODE1fQ",
    "hasMore": true,
    "total": 1,
    "isTotalCapped": true
  }
}

Return one job

GET/v1/jobs/{jobId}jobs.get

Try it on developer.ken.so

Requires type because the same numeric id can exist in more than one source. An inbox_import job carries inboxImport with counts and per-row results; one with no progress for 10 minutes reads failed with error.codeinterrupted. A missing or cross-workspace id is not_found, and so is another member's knowledge_export. Read-only. Each type needs what its own routes need, as on the list; without it the call is 403 permission_denied. A scraping job's status read sets X-Ken-Web-Source and X-Ken-Credits-Charged: Kenso's key charges a job as its reads report progress. A crawl or batch scrape returns one Firecrawl status page (about 10 MB at most) per read: when output.next is not null, pass it back as cursor to read the following page. Other types ignore cursor. A crawl or batch scrape read draws from the Heavy rate-limit class, like the legacy status routes it replaces.

Parameters

Name
In
Type
Required
Description
jobId
In: path
integer (int64)
required
type
In: query
string
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 JobModel.

Field
Type
Description
id
integer (int64)
type
string
status
string
progress
JobProgressModel
resource
JobResourceModel
createdAt
string (date-time)
downloadUrl
string
error
JobErrorModel
result
object
Upstream payload for a scraping job get. Omitted for other types and for lists.
domainsListed
integer (int32)
Listed-domain count stored by a completed domain health sweep. Omitted until that count exists.
excludedLibraryContacts
integer (int32)
Contacts from a Kenso library list a contact export left out (they are never exported), including 0. Only on contact_export jobs of kind contacts, campaign and advanced; omitted otherwise.
inboxImport
InboxImportJobModel
Counts and per-row results of an inbox_import job. Passwords are never returned.
personImport
PersonImportJobModel
Counts of a 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).
skipped
ContactImportSkipsModel
Rows a campaign 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.
Request
curl -X GET "https://api.ken.so/v1/jobs/812" \
  -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": 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
    }
  }
}

Requires Search edit, plus what the type's own routes need, as on the list (a migration job: workspace Admin). Crawl and batch scrape cancel the stored Firecrawl id. A migration job cancels like POST /v1/migration-runs/{runId}/cancel: it stays running until the engine stops it. Extraction and the other job types return 409 invalid_state. A finished scraping or migration job does too. A missing job is not_found, and so is another member's knowledge_export.

Parameters

Name
In
Type
Required
Description
jobId
In: path
integer (int64)
required
type
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 JobModel.

Field
Type
Description
id
integer (int64)
type
string
status
string
progress
JobProgressModel
resource
JobResourceModel
createdAt
string (date-time)
downloadUrl
string
error
JobErrorModel
result
object
Upstream payload for a scraping job get. Omitted for other types and for lists.
domainsListed
integer (int32)
Listed-domain count stored by a completed domain health sweep. Omitted until that count exists.
excludedLibraryContacts
integer (int32)
Contacts from a Kenso library list a contact export left out (they are never exported), including 0. Only on contact_export jobs of kind contacts, campaign and advanced; omitted otherwise.
inboxImport
InboxImportJobModel
Counts and per-row results of an inbox_import job. Passwords are never returned.
personImport
PersonImportJobModel
Counts of a 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).
skipped
ContactImportSkipsModel
Rows a campaign 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.
Request
curl -X POST "https://api.ken.so/v1/jobs/812/cancel" \
  -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": 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
    }
  }
}