Kenso

Domains

Your sending domains: settings, health, tracking DNS and nameserver checks.

Deliverability9 endpointsKen-Version: 2026-11-02AuthenticationWorkspacesErrors

Parameters

Name
In
Type
Required
Description
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 DomainModel. Each item has these fields. The response also carries pagination.

Field
Type
Description
id
integer (int64)
name
string
status
string
source
string
expirationDate
string (date-time)
daysLeft
integer (int32)
isExpiring
boolean
autoRenew
boolean
autoRenewEligible
boolean
registrar
string
dnsProvider
string
clickRateTrackingEnabled
boolean
trackingDnsStatus
string
maskingEnabled
boolean
rampUpDays
integer (int32)
rampUp
DomainRampUpModel
redirectUrl404
string
openPixelHostname
string
openPixelStatus
string
campaignPixelHost
CampaignPixelHostModel
catchAllEmail
string
hasError
boolean
statusReason
string
isPrimary
boolean
True when this is one of the workspace's own domains (its email domain or a domain listed under Settings > Company), the domains members' primary inboxes sit on (same rule as isPrimary on an inbox). Derived on read.
tagIds
array of integer (int64)
retirement
DomainRetirementModel
A retired domain's capture window: its mail goes to Kenso's reply catch so replies to past sends still arrive, until Ken.Scraper.API.Canonical.DomainRetirementModel.CaptureUntil.
replacedBy
DomainReplacementModel
The domain that replaced another.
Request
curl -X GET "https://api.ken.so/v1/domains" \
  -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,
      "name": "string",
      "status": "string",
      "source": "string",
      "expirationDate": "2026-09-23T15:02:11Z",
      "daysLeft": 1,
      "isExpiring": true,
      "autoRenew": true,
      "autoRenewEligible": true,
      "registrar": "string",
      "dnsProvider": "string",
      "clickRateTrackingEnabled": true,
      "trackingDnsStatus": "string",
      "maskingEnabled": true,
      "rampUpDays": 1,
      "rampUp": {
        "days": 1,
        "dayIndex": 1,
        "isComplete": true
      },
      "redirectUrl404": "string",
      "openPixelHostname": "string",
      "openPixelStatus": "string",
      "campaignPixelHost": {
        "status": "string",
        "hostname": "string",
        "requiredRecord": {
          "type": "string",
          "name": "string",
          "value": "string"
        }
      },
      "catchAllEmail": "[email protected]",
      "hasError": true,
      "statusReason": "string",
      "isPrimary": true,
      "tagIds": [
        812
      ],
      "retirement": {
        "state": "string",
        "captureUntil": "2026-09-23T15:02:11Z",
        "releasedAt": "2026-09-23T15:02:11Z",
        "renewalEndsWindowEarly": true
      },
      "replacedBy": {
        "id": 812,
        "name": "string"
      }
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6ODE1fQ",
    "hasMore": true,
    "total": 1,
    "isTotalCapped": true
  }
}

Requires WriteAccess. Auto-renew requires Delivery edit and the Billing feature. Masking and catch-all require SuperAdmin. websiteMode (redirect or page) records the person's answer to "rebuild or redirect"; it cannot be cleared.

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: object.

Response 200

data is a DomainBulkResult.

Field
Type
Description
updatedCount
integer (int32)
failed
array of DomainBulkFailure
Request
curl -X POST "https://api.ken.so/v1/domains/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 '{}'
Response 200
{
  "success": true,
  "data": {
    "updatedCount": 1,
    "failed": [
      {
        "id": 812,
        "message": "string"
      }
    ]
  }
}

Parameters

Name
In
Type
Required
Description
domainId
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 200

data is a DomainModel.

Field
Type
Description
id
integer (int64)
name
string
status
string
source
string
expirationDate
string (date-time)
daysLeft
integer (int32)
isExpiring
boolean
autoRenew
boolean
autoRenewEligible
boolean
registrar
string
dnsProvider
string
clickRateTrackingEnabled
boolean
trackingDnsStatus
string
maskingEnabled
boolean
rampUpDays
integer (int32)
rampUp
DomainRampUpModel
redirectUrl404
string
openPixelHostname
string
openPixelStatus
string
campaignPixelHost
CampaignPixelHostModel
catchAllEmail
string
hasError
boolean
statusReason
string
isPrimary
boolean
True when this is one of the workspace's own domains (its email domain or a domain listed under Settings > Company), the domains members' primary inboxes sit on (same rule as isPrimary on an inbox). Derived on read.
tagIds
array of integer (int64)
retirement
DomainRetirementModel
A retired domain's capture window: its mail goes to Kenso's reply catch so replies to past sends still arrive, until Ken.Scraper.API.Canonical.DomainRetirementModel.CaptureUntil.
replacedBy
DomainReplacementModel
The domain that replaced another.
Request
curl -X GET "https://api.ken.so/v1/domains/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,
    "name": "string",
    "status": "string",
    "source": "string",
    "expirationDate": "2026-09-23T15:02:11Z",
    "daysLeft": 1,
    "isExpiring": true,
    "autoRenew": true,
    "autoRenewEligible": true,
    "registrar": "string",
    "dnsProvider": "string",
    "clickRateTrackingEnabled": true,
    "trackingDnsStatus": "string",
    "maskingEnabled": true,
    "rampUpDays": 1,
    "rampUp": {
      "days": 1,
      "dayIndex": 1,
      "isComplete": true
    },
    "redirectUrl404": "string",
    "openPixelHostname": "string",
    "openPixelStatus": "string",
    "campaignPixelHost": {
      "status": "string",
      "hostname": "string",
      "requiredRecord": {
        "type": "string",
        "name": "string",
        "value": "string"
      }
    },
    "catchAllEmail": "[email protected]",
    "hasError": true,
    "statusReason": "string",
    "isPrimary": true,
    "tagIds": [
      812
    ],
    "retirement": {
      "state": "string",
      "captureUntil": "2026-09-23T15:02:11Z",
      "releasedAt": "2026-09-23T15:02:11Z",
      "renewalEndsWindowEarly": true
    },
    "replacedBy": {
      "id": 812,
      "name": "string"
    }
  }
}

Update a domain

PATCH/v1/domains/{domainId}domains.update

Try it on developer.ken.so

Absent fields stay unchanged. Null clears text fields and tag ids.

Requires WriteAccess. Auto-renew requires Delivery edit and the Billing feature. Masking and catch-all require SuperAdmin. websiteMode (redirect or page) records the person's answer to "rebuild or redirect"; it cannot be cleared.

Parameters

Name
In
Type
Required
Description
domainId
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: object.

Response 200

data is a DomainModel.

Field
Type
Description
id
integer (int64)
name
string
status
string
source
string
expirationDate
string (date-time)
daysLeft
integer (int32)
isExpiring
boolean
autoRenew
boolean
autoRenewEligible
boolean
registrar
string
dnsProvider
string
clickRateTrackingEnabled
boolean
trackingDnsStatus
string
maskingEnabled
boolean
rampUpDays
integer (int32)
rampUp
DomainRampUpModel
redirectUrl404
string
openPixelHostname
string
openPixelStatus
string
campaignPixelHost
CampaignPixelHostModel
catchAllEmail
string
hasError
boolean
statusReason
string
isPrimary
boolean
True when this is one of the workspace's own domains (its email domain or a domain listed under Settings > Company), the domains members' primary inboxes sit on (same rule as isPrimary on an inbox). Derived on read.
tagIds
array of integer (int64)
retirement
DomainRetirementModel
A retired domain's capture window: its mail goes to Kenso's reply catch so replies to past sends still arrive, until Ken.Scraper.API.Canonical.DomainRetirementModel.CaptureUntil.
replacedBy
DomainReplacementModel
The domain that replaced another.
Request
curl -X PATCH "https://api.ken.so/v1/domains/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 '{}'
Response 200
{
  "success": true,
  "data": {
    "id": 812,
    "name": "string",
    "status": "string",
    "source": "string",
    "expirationDate": "2026-09-23T15:02:11Z",
    "daysLeft": 1,
    "isExpiring": true,
    "autoRenew": true,
    "autoRenewEligible": true,
    "registrar": "string",
    "dnsProvider": "string",
    "clickRateTrackingEnabled": true,
    "trackingDnsStatus": "string",
    "maskingEnabled": true,
    "rampUpDays": 1,
    "rampUp": {
      "days": 1,
      "dayIndex": 1,
      "isComplete": true
    },
    "redirectUrl404": "string",
    "openPixelHostname": "string",
    "openPixelStatus": "string",
    "campaignPixelHost": {
      "status": "string",
      "hostname": "string",
      "requiredRecord": {
        "type": "string",
        "name": "string",
        "value": "string"
      }
    },
    "catchAllEmail": "[email protected]",
    "hasError": true,
    "statusReason": "string",
    "isPrimary": true,
    "tagIds": [
      812
    ],
    "retirement": {
      "state": "string",
      "captureUntil": "2026-09-23T15:02:11Z",
      "releasedAt": "2026-09-23T15:02:11Z",
      "renewalEndsWindowEarly": true
    },
    "replacedBy": {
      "id": 812,
      "name": "string"
    }
  }
}

Delete a domain

DELETE/v1/domains/{domainId}domains.delete

Try it on developer.ken.so

Returns 204. Requires WriteAccess.

Parameters

Name
In
Type
Required
Description
domainId
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/domains/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

Return the latest health snapshot for one domain

GET/v1/domains/{domainId}/healthdomains.get-health

Try it on developer.ken.so

Blacklist, mail DNS, bounce, placement, nameserver, and certificate state. spfStatus, dkimStatus, dmarcStatus and mxStatus are pass, fail or unknown, omitted before the first check. They and the blacklist come from the last health snapshot (the daily health sweep, or POST /v1/domain-health-checks, a 202 job) dated by checkedAt, and do not change until the next check runs. Rates are fractions from 0 to 1. A domain outside the workspace is not_found.

Parameters

Name
In
Type
Required
Description
domainId
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 200

data is a DomainHealthModel.

Field
Type
Description
domainId
integer (int64)
name
string
blacklistStatus
string
listedCount
integer (int32)
listedZones
array of string
checkedAt
string (date-time)
spfStatus
string
dkimStatus
string
dmarcStatus
string
mxStatus
string
hasSpf
boolean
hasDkim
boolean
hasDmarc
boolean
hasMx
boolean
isChecked
boolean
dkimSelector
string
bounceRate
number (double)
bounceStatus
string
bounceCheckedAt
string (date-time)
bounceEmailCount
integer (int32)
bouncedEmailCount
integer (int32)
inboxRate
number (double)
spamRate
number (double)
placementStatus
string
placementCompletedAt
string (date-time)
infraguardStatus
string
nameserverStatus
string
nameservers
array of string
sslStatus
string
sslExpiresAt
string (date-time)
ipAbuseScore
integer (int32)
Stored AbuseIPDB score. Omitted when the check has none.
Request
curl -X GET "https://api.ken.so/v1/domains/812/health" \
  -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": {
    "domainId": 812,
    "name": "string",
    "blacklistStatus": "string",
    "listedCount": 1,
    "listedZones": [
      "string"
    ],
    "checkedAt": "2026-09-23T15:02:11Z",
    "spfStatus": "string",
    "dkimStatus": "string",
    "dmarcStatus": "string",
    "mxStatus": "string",
    "hasSpf": true,
    "hasDkim": true,
    "hasDmarc": true,
    "hasMx": true,
    "isChecked": true,
    "dkimSelector": "string",
    "bounceRate": 0.5,
    "bounceStatus": "string",
    "bounceCheckedAt": "2026-09-23T15:02:11Z",
    "bounceEmailCount": 1,
    "bouncedEmailCount": 1,
    "inboxRate": 0.5,
    "spamRate": 0.5,
    "placementStatus": "string",
    "placementCompletedAt": "2026-09-23T15:02:11Z",
    "infraguardStatus": "string",
    "nameserverStatus": "string",
    "nameservers": [
      "string"
    ],
    "sslStatus": "string",
    "sslExpiresAt": "2026-09-23T15:02:11Z",
    "ipAbuseScore": 1
  }
}

Return tracking DNS state for one domain

GET/v1/domains/{domainId}/dnsdomains.get-dns

Try it on developer.ken.so

Parameters

Name
In
Type
Required
Description
domainId
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 200

data is a DomainDnsModel.

Field
Type
Description
trackingStatus
string
clickRateTrackingEnabled
boolean
openPixelHostname
string
openPixelStatus
string
lastError
string
checkedAt
string (date-time)
Request
curl -X GET "https://api.ken.so/v1/domains/812/dns" \
  -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": {
    "trackingStatus": "string",
    "clickRateTrackingEnabled": true,
    "openPixelHostname": "string",
    "openPixelStatus": "string",
    "lastError": "string",
    "checkedAt": "2026-09-23T15:02:11Z"
  }
}

Verify Kenso tracking DNS for one domain

POST/v1/domains/{domainId}/verify-dnsdomains.verify-dns

Try it on developer.ken.so

Requires WriteAccess.

Parameters

Name
In
Type
Required
Description
domainId
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 200

data is a DomainDnsModel.

Field
Type
Description
trackingStatus
string
clickRateTrackingEnabled
boolean
openPixelHostname
string
openPixelStatus
string
lastError
string
checkedAt
string (date-time)
Request
curl -X POST "https://api.ken.so/v1/domains/812/verify-dns" \
  -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": {
    "trackingStatus": "string",
    "clickRateTrackingEnabled": true,
    "openPixelHostname": "string",
    "openPixelStatus": "string",
    "lastError": "string",
    "checkedAt": "2026-09-23T15:02:11Z"
  }
}

Check imported-domain nameservers against the Kenso Cloudflare zone

POST/v1/domains/{domainId}/check-nameserversdomains.check-nameservers

Try it on developer.ken.so

Requires Delivery edit access (owners, admins and editors by default).

Parameters

Name
In
Type
Required
Description
domainId
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 200

data is a DomainNameserverCheckModel.

Field
Type
Description
domainId
integer (int64)
name
string
status
string
zoneStatus
string
activated
boolean
expectedNameservers
array of string
waitingForCredits
boolean
The zone is active but activation waits until the workspace can pay the first month of the pending mailboxes.
requiredMillicredits
integer (int64)
Set with Ken.Scraper.API.Canonical.DomainNameserverCheckModel.WaitingForCredits: the first month of the pending mailboxes.
availableMillicredits
integer (int64)
Set with Ken.Scraper.API.Canonical.DomainNameserverCheckModel.WaitingForCredits: the workspace's total balance.
Request
curl -X POST "https://api.ken.so/v1/domains/812/check-nameservers" \
  -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": {
    "domainId": 812,
    "name": "string",
    "status": "string",
    "zoneStatus": "string",
    "activated": true,
    "expectedNameservers": [
      "string"
    ],
    "waitingForCredits": true,
    "requiredMillicredits": 1,
    "availableMillicredits": 1
  }
}