Kenso

Blocklist entries

Emails and domains Kenso never contacts: add, import from CSV, annotate and remove.

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

Add up to 1,000 blocklist values of one type

POST/v1/blocklist-entries/bulk-createblocklist-entries.bulk-create

Try it on developer.ken.so

Send values, or entries ([{ "value": "...", "reason": "..." }]) for a reason per value, not both. Optional reason applies to every value without its own. Per-value outcomes are succeeded or failed. Duplicates stay failed with already_exists and keep their own reason. A domain a customer account or a blocklist rule already lists becomes manual under its id, with the reason sent, and is in succeeded with claimed: true, as on the single add. A shared mail provider domain (gmail.com, hotmail.co.uk, web.de) fails with shared_mail_provider; any other malformed value with invalid. To undo the add, bulk-delete only the succeeded ids without claimed: true: a claimed entry was blocked before the add, and deleting it unblocks the domain. Requires WriteAccess.

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
type
string
optional
values
array of string
optional
The values to block. Send this or Ken.Scraper.API.Dtos.BulkCreateBlocklistEntriesRequest.Entries, not both.
reason
string
optional
Why every value is blocked. Optional, at most 200 characters. An entry's own reason wins over it.
entries
array of BulkCreateBlocklistEntry
optional
Values with their own reason, such as a CSV reason column. Send this or Ken.Scraper.API.Dtos.BulkCreateBlocklistEntriesRequest.Values, not both.

Response 200

data is a BlocklistBulkResult.

Field
Type
Description
succeeded
array of BlocklistEntryModel
failed
array of BlocklistBulkFailure
Request
curl -X POST "https://api.ken.so/v1/blocklist-entries/bulk-create" \
  -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 '{
  "type": "string",
  "values": [
    "string"
  ],
  "reason": "string",
  "entries": [
    {
      "value": "string",
      "reason": "string"
    }
  ]
}'
Response 200
{
  "success": true,
  "data": {
    "succeeded": [
      {
        "id": 7712,
        "type": "domain",
        "value": "competitor.example.com",
        "createdAt": "2026-09-23T15:02:11Z",
        "source": "manual",
        "reason": "Current customer"
      }
    ],
    "failed": [
      {
        "value": "string",
        "code": "string",
        "message": "string"
      }
    ]
  }
}

Remove up to 1,000 blocklist entries by id

POST/v1/blocklist-entries/bulk-deleteblocklist-entries.bulk-delete

Try it on developer.ken.so

Body { "ids": [...] }. Removes them in one transaction and runs the own-domain and rule reconciles once, so undoing a large upload takes one call per 1,000 entries. To undo a bulk add, send only its succeeded ids without claimed: true: a claimed entry was blocked before the add (by a customer account or a rule), and a customer entry deleted here stays off. succeeded lists every id that is off the blocklist after the call, in request order, including an id already gone. An own-domain entry, and a rule entry while blocklist rules are on, stay and are in failed with invalid_state and the single delete's message. Requires WriteAccess.

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
ids
array of integer (int64)
optional
The entry ids to remove, at most 1,000.

Response 200

data is a BlocklistBulkDeleteResult.

Field
Type
Description
succeeded
array of integer (int64)
Every id off the blocklist after the call, removed now or already gone, in request order.
failed
array of BlocklistBulkDeleteFailure
Request
curl -X POST "https://api.ken.so/v1/blocklist-entries/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
  ]
}'
Response 200
{
  "success": true,
  "data": {
    "succeeded": [
      1
    ],
    "failed": [
      {
        "id": 812,
        "error": {
          "code": "string",
          "message": "string"
        }
      }
    ]
  }
}

Ordered by id, which follows creation: sort=createdAt (the default) is oldest first, sort=-createdAt newest first; keep the same sort while paging. Optional filters: type (email or domain), value (an exact match), q (a case-insensitive substring of the value or the reason), source (comma-separated manual, own_domain, customer, rule) and hasReason. includeTotal=true adds pagination.total, every entry the filters match. includeCounts=true adds counts: the workspace's entries in all, emails, domains, from the CRM (customer and rule) and with no reason, whatever the filters. Requires ReadAccess.

Parameters

Name
In
Type
Required
Description
Type
In: query
string
optional
Value
In: query
string
optional
Q
In: query
string
optional
Case-insensitive substring of the value or the reason.
Source
In: query
string
optional
Comma-separated sources, any of manual, own_domain, customer and rule.
HasReason
In: query
boolean
optional
true lists entries with a reason, false those without one.
Sort
In: query
string
optional
createdAt (oldest first, the default) or -createdAt (newest first).
IncludeTotal
In: query
boolean
optional
true adds pagination.total, every entry the filters match.
IncludeCounts
In: query
boolean
optional
true adds counts, the workspace's entries per filter.
Cursor
In: query
string
optional
Limit
In: query
integer (int32)
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 BlocklistEntryModel. Each item has these fields. The response also carries pagination, counts.

Field
Type
Description
id
integer (int64)
type
string
value
string
createdAt
string (date-time)
source
string
manual, or own_domain for a domain mirrored from the workspace's own domains. An own_domain entry cannot be deleted here (409 invalid_state); remove the domain in Settings > Company instead, or ask Kenso support to change the Primary domain. customer for a domain of an account marked a customer; clearing the account's Customer flag removes it. rule for a domain a blocklist rule adds from Kenso's CRM: it comes off once no enabled rule matches it, and it cannot be deleted here (409 invalid_state); change or turn off the rule instead. Adding the same value here makes it manual.
reason
string
Why the value is blocked, at most 200 characters. Omitted when the entry has none. Kenso sets it on rows it adds (Opted out or bounced, Customer in HubSpot, Customer account); own-domain rows have none.
claimed
boolean
true on a create or bulk-create result when a customer account or a blocklist rule already listed the domain and this call made that entry manual, same id. Omitted otherwise.
Request
curl -X GET "https://api.ken.so/v1/blocklist-entries" \
  -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": 7712,
      "type": "domain",
      "value": "competitor.example.com",
      "createdAt": "2026-09-23T15:02:11Z",
      "source": "manual",
      "reason": "Current customer"
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6ODE1fQ",
    "hasMore": true,
    "total": 1,
    "isTotalCapped": true
  },
  "counts": {
    "all": 1,
    "emails": 1,
    "domains": 1,
    "fromCrm": 1,
    "noReason": 1
  }
}

Add one email or domain to the blocklist

POST/v1/blocklist-entriesblocklist-entries.create

Try it on developer.ken.so

Optional reason (at most 200 characters) says why the value is blocked. A duplicate entry is validation_failed and keeps its own reason. A domain a customer account or a blocklist rule already lists becomes manual under its id, with this reason, and comes back with claimed: true. A shared mail provider domain (gmail.com, hotmail.co.uk, web.de) is validation_failed with detail code shared_mail_provider: block those addresses one by one. Requires WriteAccess.

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
type
string
optional
value
string
optional
reason
string
optional
Why the value is blocked. Optional, at most 200 characters; blank stores none.

Response 201

data is a BlocklistEntryModel.

Field
Type
Description
id
integer (int64)
type
string
value
string
createdAt
string (date-time)
source
string
manual, or own_domain for a domain mirrored from the workspace's own domains. An own_domain entry cannot be deleted here (409 invalid_state); remove the domain in Settings > Company instead, or ask Kenso support to change the Primary domain. customer for a domain of an account marked a customer; clearing the account's Customer flag removes it. rule for a domain a blocklist rule adds from Kenso's CRM: it comes off once no enabled rule matches it, and it cannot be deleted here (409 invalid_state); change or turn off the rule instead. Adding the same value here makes it manual.
reason
string
Why the value is blocked, at most 200 characters. Omitted when the entry has none. Kenso sets it on rows it adds (Opted out or bounced, Customer in HubSpot, Customer account); own-domain rows have none.
claimed
boolean
true on a create or bulk-create result when a customer account or a blocklist rule already listed the domain and this call made that entry manual, same id. Omitted otherwise.
Request
curl -X POST "https://api.ken.so/v1/blocklist-entries" \
  -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 '{
  "type": "domain",
  "value": "competitor.example.com",
  "reason": "Current customer"
}'
Response 201
{
  "success": true,
  "data": {
    "id": 7712,
    "type": "domain",
    "value": "competitor.example.com",
    "createdAt": "2026-09-23T15:02:11Z",
    "source": "manual",
    "reason": "Current customer"
  }
}

Set or clear why a blocklist entry is blocked

PATCH/v1/blocklist-entries/{entryId}blocklist-entries.update

Try it on developer.ken.so

Body { "reason": "..." }, at most 200 characters; null or blank clears it. reason is required. Requires WriteAccess. An entry outside the workspace is not_found.

Parameters

Name
In
Type
Required
Description
entryId
In: path
integer (int64)
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
reason
string
optional
Why the value is blocked, at most 200 characters. Null or blank clears it.

Response 200

data is a BlocklistEntryModel.

Field
Type
Description
id
integer (int64)
type
string
value
string
createdAt
string (date-time)
source
string
manual, or own_domain for a domain mirrored from the workspace's own domains. An own_domain entry cannot be deleted here (409 invalid_state); remove the domain in Settings > Company instead, or ask Kenso support to change the Primary domain. customer for a domain of an account marked a customer; clearing the account's Customer flag removes it. rule for a domain a blocklist rule adds from Kenso's CRM: it comes off once no enabled rule matches it, and it cannot be deleted here (409 invalid_state); change or turn off the rule instead. Adding the same value here makes it manual.
reason
string
Why the value is blocked, at most 200 characters. Omitted when the entry has none. Kenso sets it on rows it adds (Opted out or bounced, Customer in HubSpot, Customer account); own-domain rows have none.
claimed
boolean
true on a create or bulk-create result when a customer account or a blocklist rule already listed the domain and this call made that entry manual, same id. Omitted otherwise.
Request
curl -X PATCH "https://api.ken.so/v1/blocklist-entries/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 '{
  "reason": "string"
}'
Response 200
{
  "success": true,
  "data": {
    "id": 7712,
    "type": "domain",
    "value": "competitor.example.com",
    "createdAt": "2026-09-23T15:02:11Z",
    "source": "manual",
    "reason": "Current customer"
  }
}

Remove one blocklist entry

DELETE/v1/blocklist-entries/{entryId}blocklist-entries.delete

Try it on developer.ken.so

Requires WriteAccess. An entry outside the workspace is not_found.

Parameters

Name
In
Type
Required
Description
entryId
In: path
integer (int64)
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/blocklist-entries/812" \
  -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

Import blocklist rows from a CSV file

POST/v1/blocklist-entries/importsblocklist-entries.import

Try it on developer.ken.so

Multipart field file is a .csv with email and/or domain columns and an optional reason column; a cell over 200 characters is cut, never failing the file. Optional form field reason (at most 200 characters) applies to every row without its own. Rows already on the blocklist keep their own reason, and a shared mail provider in the domain column (gmail.com) is skipped. Requires WriteAccess.

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

multipart/form-data, optional.

Field
Type
Required
Description
file
string (binary)
optional
reason
string
optional

Response 200

data is a BlocklistImportModel.

Field
Type
Description
status
string
Request
curl -X POST "https://api.ken.so/v1/blocklist-entries/imports" \
  -H "Authorization: Bearer $KEN_API_KEY" \
  -H "Ken-Version: 2026-11-02" \
  -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
  -F "file=@./file" \
  -F 'reason=string'
Response 200
{
  "success": true,
  "data": {
    "status": "string"
  }
}