Kenso

Agent team

Actions taken by Kenso's agent team, with undo, and its runway.

AI6 endpointsKen-Version: 2026-11-02AuthenticationWorkspacesErrors

Return how long each live campaign's leads last and whether its inboxes can carry the send

GET/v1/agent-team/runwayagent-team.get-runway

Needs the agent_templates feature on your workspace. Until it is on, calls answer 404.

Try it on developer.ken.so

Without campaignId: the workspace's live campaigns (scheduled, sending, launching), newest first, at most 50. With it: that campaign in any status, 404 when it is not in the workspace. Per campaign: Autopilot, the leads waiting for their first email and the days they last at the last 7 days' rate, the daily cap against the healthy inboxes' limits, each inbox's 7-day sends and bounce rate and why it is sick, the latest placement test, and the email interested replies. Reads only. Campaigns view.

Parameters

Name
In
Type
Required
Description
campaignId
In: query
integer (int64)
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 RunwayModel.

Field
Type
Description
workspace
RunwayWorkspaceModel
campaigns
array of RunwayCampaignModel
Request
curl -X GET "https://api.ken.so/v1/agent-team/runway" \
  -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": {
    "workspace": {
      "targetInterestedPerWeek": 1,
      "runwayDays": 1,
      "clientWorkspace": true
    },
    "campaigns": [
      {
        "campaignId": 812,
        "name": "string",
        "sendingStatus": "string",
        "autopilot": {
          "on": true,
          "audienceApproved": true,
          "weeklyTopUpLimit": 1,
          "toppedUpLast7Days": 1
        },
        "leads": {
          "notStarted": 1,
          "firstTouchesPerDay": 0.5,
          "runwayDays": 1
        },
        "capacity": {
          "dailyCap": 1,
          "rampFloor": 1,
          "inboxCapacity": 1,
          "healthyInboxCapacity": 1,
          "short": true
        },
        "inboxes": [
          {
            "inboxId": 812,
            "email": "[email protected]",
            "dailyLimit": 1,
            "sends7d": 1,
            "bounceRate7d": 0.5,
            "sick": true,
            "sickReason": "string"
          }
        ],
        "placement": {
          "completedAt": "2026-09-23T15:02:11Z",
          "inboxRate": 0.5,
          "spamRate": 0.5
        },
        "replies": {
          "interested7d": 1,
          "unansweredInterested": 1
        }
      }
    ]
  }
}

Ask for one bounded change to a campaign: applied when it is inside Autopilot and the bounds, else proposed

POST/v1/agent-team/actionsagent-team.create-action

Needs the agent_templates feature on your workspace. Until it is on, calls answer 404.

Try it on developer.ken.so

Body: kind (cap_move, inbox_drop, inbox_restore, top_up, placement_test or make_default), campaignId, args for the kind, reason (up to 500 characters) and an optional idempotencyKey (up to 120). Every outcome is 200 with status: applied (the change is made and recorded as the caller's, with actionId and the undo deadline), proposed (Autopilot is off, a standing rule holds the campaign, or the change is outside the bounds: a person decides it in Approvals, approvalId), or refused (code and message; nothing changed). A lead top-up runs as a person, so an API key with no user is refused needs_a_user, and it also needs Search view and the Import permission (else 403permission_denied). A retry with the same key, or without one the same request on the same UTC day, runs once; without a key a try that failed runs again. The tool that sent it (X-Ken-Client) names the caller in the history. Campaigns edit.

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
kind
string
optional
cap_move, inbox_drop, inbox_restore, top_up, placement_test or make_default. Required.
campaignId
integer (int64)
optional
The campaign the action changes. Required.
args
map of JsonNode
optional
The kind's arguments: cap_move{ newCap }, inbox_drop{ inboxId, scope } (campaign, the default when scope is absent, or inbox for every campaign it sends on), inbox_restore{ inboxId }, top_up{ count } (the caller also needs Search view and the Import permission), placement_test{}, make_default{ experimentId }. Absent is {}.
reason
string
optional
Why, in one or two sentences a person reads, up to 500 characters. Required.
idempotencyKey
string
optional
The caller's key for this request, up to 120 characters: a retry with the same key runs once. Absent, the same kind, campaign and args run once per UTC day, and a try that failed runs again.

Response 200

data is a AgentActionOutcomeModel.

Field
Type
Description
status
string
applied, proposed (a person decides it in Approvals) or refused.
actionId
integer (int64)
The applied action; undo it with POST /v1/agent-team/actions/{actionId}/undo. Applied only.
undoUntil
string (date-time)
Until when the action can be undone; omitted when the kind has no undo. Applied only.
summary
string
What changed, in a sentence. Applied only.
approvalId
string
The proposal, request_<id>, as /v1/approvals lists it. Proposed only.
why
string
Why a person has to decide (Autopilot off, a standing rule, outside the bounds). Proposed only.
code
string
unknown_kind, kind_not_allowed, invalid_args, campaign_not_found, campaign_paused, workspace_suspended, apply_failed, needs_a_user, already_undone (the key's action was undone: send a new key) or busy (another change to the campaign is being checked: retry). Refused only.
message
string
Why it was refused, for a person. Refused only.
Request
curl -X POST "https://api.ken.so/v1/agent-team/actions" \
  -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 '{
  "kind": "string",
  "campaignId": 812,
  "args": {
    "key": {
      "options": {
        "propertyNameCaseInsensitive": true
      },
      "parent": {},
      "root": {}
    }
  },
  "reason": "string",
  "idempotencyKey": "string"
}'
Response 200
{
  "success": true,
  "data": {
    "status": "string",
    "actionId": 812,
    "undoUntil": "2026-09-23T15:02:11Z",
    "summary": "string",
    "approvalId": "string",
    "why": "string",
    "code": "string",
    "message": "string"
  }
}

Undo an applied agent action inside its undo window

POST/v1/agent-team/actions/{actionId}/undoagent-team.undo-action

Needs the agent_templates feature on your workspace. Until it is on, calls answer 404.

Try it on developer.ken.so

Puts back what the action changed, as the caller: the previous cap, the dropped inbox, the default before; a top-up removes only the leads that have not started (no email sent or queued). 404 when the action is not in the workspace; 400 when it is already undone or failed, its window has closed, or the undo would overwrite a newer change (the action stays in effect with the reason). Returns the action. Campaigns edit.

Parameters

Name
In
Type
Required
Description
actionId
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 AgentActionModel.

Field
Type
Description
actionId
integer (int64)
status
string
applied, undone, undo_failed or failed.
undoneAt
string (date-time)
keptLeads
integer (int32)
A top-up only: the leads it added that the undo kept because the sequencer had started them. Omitted for any other kind.
Request
curl -X POST "https://api.ken.so/v1/agent-team/actions/812/undo" \
  -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": {
    "actionId": 812,
    "status": "string",
    "undoneAt": "2026-09-23T15:02:11Z",
    "keptLeads": 1
  }
}

Return what changed on the workspace's campaigns since a time, by default since the caller last asked

GET/v1/agent-team/changesagent-team.list-changes

Needs the agent_templates feature on your workspace. Until it is on, calls answer 404.

Try it on developer.ken.so

since (ISO 8601) defaults to the caller's previous call from the same tool (X-Ken-Client), else 7 days ago, and is never more than 30 days back. Without campaignId the change log covers the live campaigns (scheduled, sending, launching). Returns the change log rows (newest first, at most 200, truncated when there were more) with who made each and its requestId, the agent actions applied (an undone top-up with the leads it kept), the proposals open now and those decided in the window, and the standing rules in force. Reads only. Campaigns view; proposals is null unless the caller also has Campaigns edit and Approve, as Approvals.

Parameters

Name
In
Type
Required
Description
since
In: query
string (date-time)
optional
campaignId
In: query
integer (int64)
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 AgentTeamChangesModel.

Field
Type
Description
since
string (date-time)
until
string (date-time)
truncated
boolean
More than 200 changes: only the newest 200 are listed.
changes
array of AgentTeamChangeModel
actions
array of AgentTeamChangedActionModel
proposals
AgentTeamProposalsModel
standingRules
array of AgentStandingRuleSummaryModel
Request
curl -X GET "https://api.ken.so/v1/agent-team/changes" \
  -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": {
    "since": "2026-09-23T15:02:11Z",
    "until": "2026-09-23T15:02:11Z",
    "truncated": true,
    "changes": [
      {
        "campaignId": 812,
        "occurredAt": "2026-09-23T15:02:11Z",
        "kind": "string",
        "actor": {
          "kind": "string",
          "label": "string"
        },
        "requestId": "string",
        "diff": {
          "key": {
            "options": {},
            "parent": {},
            "root": {}
          }
        }
      }
    ],
    "actions": [
      {
        "actionId": 812,
        "kind": "string",
        "campaignId": 812,
        "status": "string",
        "appliedAt": "2026-09-23T15:02:11Z",
        "undoUntil": "2026-09-23T15:02:11Z",
        "actorLabel": "string",
        "authority": "string",
        "keptLeads": 1
      }
    ],
    "proposals": {
      "open": [
        {
          "id": "string",
          "kind": "string",
          "status": "string",
          "campaignId": 812,
          "title": "string",
          "reason": "string",
          "args": {
            "key": {}
          },
          "urgent": true,
          "requiresClientYes": true,
          "requestedBy": {
            "kind": "string",
            "label": "string"
          },
          "createdAt": "2026-09-23T15:02:11Z",
          "expiresAt": "2026-09-23T15:02:11Z",
          "decidedAt": "2026-09-23T15:02:11Z",
          "decidedBy": {
            "userId": 812,
            "name": "string"
          },
          "error": "string"
        }
      ],
      "decided": [
        {
          "id": "string",
          "kind": "string",
          "status": "string",
          "campaignId": 812,
          "title": "string",
          "reason": "string",
          "args": {
            "key": {}
          },
          "urgent": true,
          "requiresClientYes": true,
          "requestedBy": {
            "kind": "string",
            "label": "string"
          },
          "createdAt": "2026-09-23T15:02:11Z",
          "expiresAt": "2026-09-23T15:02:11Z",
          "decidedAt": "2026-09-23T15:02:11Z",
          "decidedBy": {
            "userId": 812,
            "name": "string"
          },
          "error": "string"
        }
      ]
    },
    "standingRules": [
      {
        "ruleId": 812,
        "campaignId": 812,
        "text": "string",
        "expiresAt": "2026-09-23T15:02:11Z",
        "author": {
          "userId": 812,
          "name": "string"
        }
      }
    ]
  }
}

List the workspace's proposals, newest first

GET/v1/agent-team/proposalsagent-team.list-proposals

Needs the agent_templates feature on your workspace. Until it is on, calls answer 404.

Try it on developer.ken.so

status: open (pending or awaiting the client) or one status as it reads now (a pending proposal past its expiry reads expired); campaignId; limit 1-100, default 25; cursor from the previous page. A status filter applies within each page, so a page can hold fewer than limit while pagination.hasMore is true. Campaigns edit and Approve, as Approvals.

Parameters

Name
In
Type
Required
Description
Status
In: query
string
optional
open (pending or awaiting the client), pending, awaiting_client, applied, rejected, expired, superseded or failed. Omit for every status.
CampaignId
In: query
integer (int64)
optional
Limit
In: query
integer (int32)
optional
1 to 100, default 25.
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 list of AgentProposalModel. Each item has these fields. The response also carries pagination.

Field
Type
Description
id
string
request_<id>, the id /v1/approvals lists it under.
kind
string
status
string
pending, awaiting_client, applied, rejected, expired, superseded or failed, as it reads now.
campaignId
integer (int64)
Omitted for a workspace-level proposal.
title
string
reason
string
args
map of JsonNode
The arguments that apply on approval.
urgent
boolean
requiresClientYes
boolean
A schedule or volume change on a client workspace: approving needs the client's yes.
requestedBy
AgentRequesterModel
Who asked: kindagent, user or api_key, and the label the card shows.
createdAt
string (date-time)
expiresAt
string (date-time)
decidedAt
string (date-time)
decidedBy
AgentTeamPersonModel
A member: the id, and the name when the member still exists.
error
string
Why it was skipped or failed to apply.
Request
curl -X GET "https://api.ken.so/v1/agent-team/proposals" \
  -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": "string",
      "kind": "string",
      "status": "string",
      "campaignId": 812,
      "title": "string",
      "reason": "string",
      "args": {
        "key": {
          "options": {
            "propertyNameCaseInsensitive": true
          },
          "parent": {},
          "root": {}
        }
      },
      "urgent": true,
      "requiresClientYes": true,
      "requestedBy": {
        "kind": "string",
        "label": "string"
      },
      "createdAt": "2026-09-23T15:02:11Z",
      "expiresAt": "2026-09-23T15:02:11Z",
      "decidedAt": "2026-09-23T15:02:11Z",
      "decidedBy": {
        "userId": 812,
        "name": "string"
      },
      "error": "string"
    }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6ODE1fQ",
    "hasMore": true,
    "total": 1,
    "isTotalCapped": true
  }
}

Propose a change a person decides in Approvals

POST/v1/agent-team/proposalsagent-team.create-proposal

Needs the agent_templates feature on your workspace. Until it is on, calls answer 404.

Try it on developer.ken.so

Body: kind, campaignId (omit for angle, standing_rule and client_update), title (up to 120 characters), reason (up to 1000), args for the kind, and optionally clientYes (the client's yes in their own words, up to 300; the approver still confirms it) and urgent. Returns 201 with the proposal, request_<id>, as /v1/approvals lists it. 400unknown_kind, kind_not_allowed or invalid_args with the reason (campaign_not_found when a campaign kind names no campaign); 404campaign_not_found when the campaign is not in the workspace, deleted or archived. The tool that sent it (X-Ken-Client) names the requester on the card. Campaigns edit.

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
kind
string
optional
What to change: cap_move, schedule, pause, resume, top_up, audience, copy, inbox_drop, inbox_restore, make_default, placement_test, standing_rule, client_update or angle. Required.
campaignId
integer (int64)
optional
The campaign it changes; omit for a workspace-level kind (angle, standing_rule, client_update).
title
string
optional
The card's title, up to 120 characters. Required.
reason
string
optional
Why, in a few sentences a person reads, up to 1000 characters. Required.
args
map of JsonNode
optional
The kind's arguments, applied as they are when a person approves. Absent is {}.
clientYes
string
optional
On a client workspace, the client's yes to a schedule or volume change in the person's own words, with who, where and when (up to 300 characters). The approver still confirms it. Omit when there is none.
urgent
boolean
optional
Puts the card first in Approvals. Default false.

Response 201

data is a AgentProposalModel.

Field
Type
Description
id
string
request_<id>, the id /v1/approvals lists it under.
kind
string
status
string
pending, awaiting_client, applied, rejected, expired, superseded or failed, as it reads now.
campaignId
integer (int64)
Omitted for a workspace-level proposal.
title
string
reason
string
args
map of JsonNode
The arguments that apply on approval.
urgent
boolean
requiresClientYes
boolean
A schedule or volume change on a client workspace: approving needs the client's yes.
requestedBy
AgentRequesterModel
Who asked: kindagent, user or api_key, and the label the card shows.
createdAt
string (date-time)
expiresAt
string (date-time)
decidedAt
string (date-time)
decidedBy
AgentTeamPersonModel
A member: the id, and the name when the member still exists.
error
string
Why it was skipped or failed to apply.
Request
curl -X POST "https://api.ken.so/v1/agent-team/proposals" \
  -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 '{
  "kind": "string",
  "campaignId": 812,
  "title": "string",
  "reason": "string",
  "args": {
    "key": {
      "options": {
        "propertyNameCaseInsensitive": true
      },
      "parent": {},
      "root": {}
    }
  },
  "clientYes": "string",
  "urgent": true
}'
Response 201
{
  "success": true,
  "data": {
    "id": "string",
    "kind": "string",
    "status": "string",
    "campaignId": 812,
    "title": "string",
    "reason": "string",
    "args": {
      "key": {
        "options": {
          "propertyNameCaseInsensitive": true
        },
        "parent": {},
        "root": {}
      }
    },
    "urgent": true,
    "requiresClientYes": true,
    "requestedBy": {
      "kind": "string",
      "label": "string"
    },
    "createdAt": "2026-09-23T15:02:11Z",
    "expiresAt": "2026-09-23T15:02:11Z",
    "decidedAt": "2026-09-23T15:02:11Z",
    "decidedBy": {
      "userId": 812,
      "name": "string"
    },
    "error": "string"
  }
}