Documentation

Kairon CLI

Search LinkedIn, build lists, run campaigns and answer replies from a terminal, a script or a cron job. It is an MCP client, not a second API, so a command and an assistant make the same call.

Install npm i -g @kairon/cli

Getting started

  1. Step 1

    Install it

    Needs Node 22.23.1 or newer. You can also run it once with npx and install nothing.

    npm i -g @kairon/cli
    npx @kairon/cli whoami
    
  2. Step 2

    Sign in

    Opens your browser and signs you in with your Kairon account. There is no API key. Credentials are stored in ~/.kairon/config.json at mode 0600.

    kairon login
    
  3. Step 3

    Check who you are

    Reports the account and the LinkedIn seat every command will run as. If this works, the rest will.

    kairon whoami
    
  4. Step 4

    Run something

    Every command prints JSON, so it pipes straight into jq. Ask for help on any group or command at any time.

    kairon chat list --unread
    kairon list --help
    

Commands

One command per tool: kairon --help lists the groups, and kairon <group> --help the commands in each. A tool name splits on its first underscore and the rest is kebab-cased, so the surface here is exactly the surface the server exposes.

This page is generated from the tool catalogue by the same functions that build kairon --help, on every release. The page and your terminal cannot disagree, because they are the same code.

kairon allowance

kairon allowance get

Read the organization's AI balance

Full description

What is left of the organization's monthly AI balance: remainingUsd (can be negative), includedUsd, usedUsd (null when it cannot be derived), and periodEndsAt when it resets.

Takes no flags.

kairon audience

kairon audience preview

Count who an audience rule would select

Full description

How many of the org's OWN leads a pipeline-audience rule selects, before any list is created or anyone is contacted.

Flags: audience preview
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--audience.include.match requiredall|anyHow this group's conditions join. `all` means a lead must satisfy EVERY condition; `any` means one is enough. Inside a single condition the fields always AND and the values in a field always OR, whatever `match` says — so `{ crmStage: ['on_hold','lost'], tagId: ['t1'] }` reads as (on_hold OR lost) AND t1.
--audience.include.conditions requiredjson array jsonThe conditions this group joins, 1 to 10. Each must name at least one field; an empty condition is refused rather than read as 'everyone'.
--audience.exclude.match all|anyHow this group's conditions join. `all` means a lead must satisfy EVERY condition; `any` means one is enough. Inside a single condition the fields always AND and the values in a field always OR, whatever `match` says — so `{ crmStage: ['on_hold','lost'], tagId: ['t1'] }` reads as (on_hold OR lost) AND t1.
--audience.exclude.conditions json array jsonThe conditions this group joins, 1 to 10. Each must name at least one field; an empty condition is refused rather than read as 'everyone'.

kairon campaign

kairon campaign activate

Activate a campaign — starts sending to real people

Full description

THIS STARTS SENDING MESSAGES TO REAL PEOPLE ON LINKEDIN, and a message already sent cannot be un-sent.

Flags: campaign activate
FlagTypeWhat it is for
--startNow booleanDefault true: enroll today's first batch immediately instead of waiting for the next send window to open.
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.

kairon campaign check-accepts

Check LinkedIn for new accepts

Full description

Ask LinkedIn now which invited leads of a campaign accepted, and move each one on to its next step.

Flags: campaign check-accepts
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.

kairon campaign copy

Who still needs a per-lead line

Full description

Per-lead slot coverage.

Flags: campaign copy
FlagTypeWhat it is for
--id requiredstring
--missingOnly booleanTrue returns only the leads still MISSING copy — the "what is left to write" read. A lead is not enrolled until every slot is filled, so these are the people the campaign is silently holding back.
--cursor string
--limit integer

kairon campaign create

Create a draft campaign

Full description

Create a draft campaign: a name and the sending seats (channelAccountIds, one or more from seat_list), and the ICP to gate enrollment on (icpId).

Flags: campaign create
FlagTypeWhat it is for
--name requiredstringThe campaign's name, for the operator to recognise it in a list. Not seen by any lead.
--channelAccountIds requiredjson array jsonThe sending seats — connected LinkedIn accounts in this org, one or more. Each new lead goes to one of them and hears from that seat for the whole sequence; every seat enrolls up to the campaign's `dailyEnrollmentLimit` a day, so the campaign's daily volume grows with each seat. Duplicates collapse. Get the ids from `seat_list` — the seats that can send right now. (`identity_get`'s `seatId` names your own account even when it is not sendable, so a campaign built on it is created, publishes fine, and is then refused by `campaign_activate` with `sender_not_connected`.)
--icpId stringThe ICP to gate enrollment on. There is no default and nothing is selected for you: omitting this creates an UNGATED campaign. ASK the operator before calling, every time — never decide it for them and never leave it unasked. Show them their ICPs (`icp_list`) and say in one line what each answer means: gated, and only people who qualify for that ICP are contacted while everyone else on their lists is skipped and never messaged; ungated, and everyone on their lists is contacted, except the people its Enrollment Filter skips (a new campaign skips anyone your seats are already in touch with: a conversation, or an invitation, message or comment a campaign sent). "No gate" is a fine answer, but it has to be one they gave.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "campaign-building" }) and of framework_get({ slug: "outreach" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon campaign get

One campaign in full — config, audience and both graphs

Full description

Read ONE campaign completely enough to REBUILD it.

Flags: campaign get
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.

kairon campaign lead-start

Start one queued person today, ahead of the pacing

Full description

Enroll one person from the campaign's audience now, instead of waiting for tomorrow's batch.

Flags: campaign lead-start
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--leadId requiredstringThe lead to start, as `campaign_runs` or `list_members` returned its id.

kairon campaign list

List the org’s campaigns

Full description

List this org's campaigns, keyset-paginated — { q?, status?, sort?, direction?, cursor?, limit? }.

Flags: campaign list
FlagTypeWhat it is for
--q stringCase-insensitive substring of the campaign's name.
--status json jsonReturn only campaigns in these statuses — one, or several as a comma-separated list (e.g. `draft,active,paused`). Omit for every status, including the finished and archived ones the app hides by default.
--initiative json jsonReturn only campaigns serving this initiative. The literal `none` returns the campaigns serving no initiative yet — the candidates an initiative can attach (PRD-79 IN8), since a campaign serves at most one.
--cursor stringOpaque keyset token from the previous page's `nextCursor`. Omit for the first page.
--limit integerCampaigns per page, 1-100.
--sort name|status|sender|updatedOrder the page by this column instead of the default one. The default puts the campaigns that are running first — active, then draft, then paused, then finished, then archived — and the most recent first inside each of those.
--direction asc|descWhich way `sort` runs. Omit it to get the column read the way the app reads it: names and senders A→Z, statuses running-first, dates newest-first.

kairon campaign pause

Pause an active campaign

Full description

Pause an active campaign.

Flags: campaign pause
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.

kairon campaign preview

Read what a step would actually send, before anyone gets it

Full description

READ THE MESSAGE BEFORE YOU ACTIVATE.

Flags: campaign preview
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--nodeKey requiredstringWhich step to preview — the `key` of a node in the stored graph, as `campaign_get` returned it. Must be a step that writes something: `send_invite`, `send_message` or `comment_on_post`. Any other type is refused, because it has no message to show you.
--leadIds json array jsonWhich real leads to draft for, at most 3. Each must already sit in this campaign's bound audience; one that does not comes back as `lead_not_in_audience` rather than failing the call. OMIT IT and the first few of the audience are sampled for you, which is what you want unless you are checking one named person.
--graph published|draftWhich stored graph to read the step from. Defaults to `published` — what the engine is actually sending — and falls back to `draft` when nothing has been published yet. Ask for `draft` to check an edit you have not published. A `{{@slot}}` in a draft-graph step previews UNRESOLVED when nobody has written that line yet, which is every slot before the first publish, since per-lead copy is written against the published graph; a slot whose name already carries copy from an earlier publish renders normally here.
--senderUserId stringWhose text to preview on a `send_message` step with per-sender versions (`bySender`): a sender's `ownerUserId` from `seat_list`. OMIT IT to preview what the campaign's first sender sends — their own version if they have one, else the step's text. A sender with no version previews the step's text.

kairon campaign publish

Validate and publish the campaign's draft graph

Full description

Validate and publish the campaign's draft graph.

Flags: campaign publish
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--migrateInFlight booleanDefault false: publishing pins the new version for FUTURE enrollments only, and runs already in flight finish on the version they started. True repoints them onto the new version by node `key` — a run parked on a step the new version removed is CANCELED, not migrated.

kairon campaign review-feed

The review desk — what is about to fire, and what is waiting on you

Full description

The operator's Tasks page, as one read: every send booked to fire (autopilot), every run waiting for approval (review), every AI draft that errored (failed), and everything already acted on today (done), plus each seat's daily budget.

Flags: campaign review-feed
FlagTypeWhat it is for
--kind autopilot|review|failed|doneWhich slice: `autopilot` (booked, about to fire), `review` (waiting for approval on a manual campaign), `failed` (the AI draft errored), `done` (already acted today). Omit for all four.
--campaignId stringOnly rows belonging to this campaign — applied to the desk WINDOW, not to the campaign. The desk holds a bounded slice of the org, so a campaign whose rows fall outside it comes back empty; `windowCapped: true` is how you tell that apart from "nothing is queued". For an exhaustive per-campaign read use `campaign_runs`, which pages with a cursor.
--limit integerRows PER KIND, 1-200, default 25 — so an unfiltered call can return up to FOUR times this. Spent per kind on purpose: one busy kind must not push the others off the page, and a `review` row is reachable from no other index. Pass `kind` to spend the whole budget on one. Raise it only when you actually need the long tail: every row carries the draft it will send.

kairon campaign run-approve

Approve a manual campaign’s parked send — it goes out

Full description

THIS SENDS THE MESSAGE.

Flags: campaign run-approve
FlagTypeWhat it is for
--runId requiredstringOne run's id — starts with `srun_`, as `campaign_runs` or `campaign_review_feed` returned it. A run is one enrolled lead. NOT a feed row's `id` or `nodeRunId`.

kairon campaign run-cancel

End these people’s sequences — nothing further is sent to them

Full description

Stop up to 100 enrolled leads: each run ends, anything drafted or booked for them is dropped, and their parked workflow is torn down so no timer fires later.

Flags: campaign run-cancel
FlagTypeWhat it is for
--runIds requiredjson array jsonThe runs to end — each starts with `srun_`, as `campaign_runs` or `campaign_review_feed` returned them. NOT a feed row's `id` or `nodeRunId`: on an `autopilot` row those name the SEND, and a batch that accepted them would report a retryable failure for an id that can never succeed.

kairon campaign run-get

One sequence run, step by step

Full description

Read ONE sequence run in full, by an id from campaign_runs.

Flags: campaign run-get
FlagTypeWhat it is for
--runId requiredstringOne run's id, as `campaign_runs` returned it — a run is one enrolled lead.

kairon campaign run-skip-step

Skip the step this person is on — their sequence goes on

Full description

Pass over the step a run is on WITHOUT ending the run: the drafted or booked message, comment, email, like, visit, follow, research or removal never happens, and the person carries straight on to the next step (or finishes, when it was the…

Flags: campaign run-skip-step
FlagTypeWhat it is for
--runId requiredstringOne run's id — starts with `srun_`, as `campaign_runs` or `campaign_review_feed` returned it. A run is one enrolled lead. NOT a feed row's `id` or `nodeRunId`.

kairon campaign run-skip-wait

Collapse the delay this run is waiting on

Full description

Cut short the delay step a run is parked on so the sequence carries straight on to its next step.

Flags: campaign run-skip-wait
FlagTypeWhat it is for
--runId requiredstringOne run's id — starts with `srun_`, as `campaign_runs` or `campaign_review_feed` returned it. A run is one enrolled lead. NOT a feed row's `id` or `nodeRunId`.

kairon campaign runs

The campaign's sequence runs

Full description

Read the campaign's sequence runs — one per enrolled lead — keyset-paginated; page with the returned cursor.

Flags: campaign runs
FlagTypeWhat it is for
--bucket waiting|didnt_accept|didnt_answer|replied|skipped|error|interestedFilter to one activity bucket: `waiting`, `didnt_accept`, `didnt_answer`, `replied`, `interested` (a subset of `replied`), `skipped` (an ICP / enrollment-filter verdict or an operator stop), or `error`. Omit for every run.
--stage json jsonActivity states to include; several read as "any of these".
--nodeKey stringOnly runs that reached this step, by the node `key` the graph gave it — including runs that have since moved past it or finished. Pair it with `dateFrom`/`dateTo` to ask who completed THIS step on those days, which is the only way to tell a first message apart from a follow-up in a sequence with more than one message step.
--q stringFind a person by name, headline, company or LinkedIn handle.
--dateFrom stringEarliest day to include, inclusive (YYYY-MM-DD). Dates each run by its LAST event — unless `nodeKey` is also set, which dates it by that step instead.
--dateTo stringLatest day to include, inclusive (YYYY-MM-DD). Dates each run by its LAST event — unless `nodeKey` is also set, which dates it by that step instead.
--listId json jsonOnly people enrolled from these source lists.
--qualificationStatus json jsonOnly people with these ICP verdicts; several read as "any of these".
--funnel invite_sent|invite_accepted|message_sent|replied|interestedOnly the people one Performance funnel card counts: `invite_sent`, `invite_accepted`, `message_sent`, `replied` or `interested`.
--cursor string
--limit integer
--id requiredstring
--includeQualification booleanAttach each run's stored qualification scorecard (the same body `qualification_get` returns for its lead). Off by default because it is BIG — every criterion with its rationale and evidence — so pair it with a small `limit` (10-25) rather than a full page.

kairon campaign seat-add

Add a sender to a campaign

Full description

Add a LinkedIn seat as a sender of a campaign (draft, active or paused).

Flags: campaign seat-add
FlagTypeWhat it is for
--channelAccountId requiredstringThe seat to add as a sender — a connected LinkedIn account in this org (`seat_list`). It takes new leads from the next enrollment; leads already running keep their own seat. Re-adding a removed sender makes it live again. Refused, naming the step, when the seat cannot run a step of the graph (an InMail step or an invite note needs Premium or Sales Navigator).
--dailyEnrollmentLimit integerThis sender's own new leads per day, 1-200. Omit to use the campaign's default (`dailyEnrollmentLimit`).
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.

kairon campaign seat-remove

Remove a sender from a campaign

Full description

Remove a sender from a campaign.

Flags: campaign seat-remove
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--channelAccountId requiredstringThe sender seat — a channel account id from the campaign view’s `seats`.
--leads requiredfinish|stopWhat happens to the leads this sender is mid-sequence with. `finish`: they keep getting their follow-ups from this sender until their sequence ends. `stop`: their runs are canceled now and nothing more is sent to them from this campaign. Either way, its leads with nothing sent yet go back to the pool for the other senders. There is no default — ask the operator.

kairon campaign seat-update

Set a sender's daily limit

Full description

Set how many new leads one sender enrolls per day for this campaign, 1-200, or null to return it to the campaign's default (dailyEnrollmentLimit on the campaign).

Flags: campaign seat-update
FlagTypeWhat it is for
--dailyEnrollmentLimit requiredjson jsonThis sender's own new leads per day, 1-200, or `null` to go back to the campaign's default.
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--channelAccountId requiredstringThe sender seat — a channel account id from the campaign view’s `seats`.

kairon campaign send-edit

Rewrite a booked send before it fires

Full description

Replace the words a drafted or scheduled send will fire with — the edited text is exactly what goes out, never re-written afterwards.

Flags: campaign send-edit
FlagTypeWhat it is for
--nodeRunId requiredstringThe booked send — starts with `nrun_`, as `campaign_review_feed` returned its `nodeRunId`. NOT the run id. Null on a feed row means nothing is drafted yet, so there is nothing to act on.
--body requiredstringThe exact text that will be sent — this REPLACES the draft, it is not an instruction to rewrite it. Empty is allowed only on a connection request, which then fires with no note. On a MESSAGE: To send this as SEVERAL messages rather than one, separate them with a line containing only `---`. Each part arrives as its own LinkedIn message a couple of seconds later, in the same conversation — what a person does when they type a short opener and then the reason they wrote. The whole thing still counts as ONE send against the daily limit. This is the same thing the "Add bubble" button does in the campaign editor. On every other send type a `---` line is sent as written.
--subject stringAn InMail subject, and only that: refused on every other send type. It is the whole of what the recipient sees before deciding to open, and a credit is spent either way.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "write-messages" }) and of framework_get({ slug: "outreach" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon campaign send-now

Fire this person’s next send immediately

Full description

THIS SENDS THE MESSAGE, sooner than anything else would have: it fires this run's next booked send NOW, outside the send window and the usual pacing.

Flags: campaign send-now
FlagTypeWhat it is for
--runId requiredstringOne run's id — starts with `srun_`, as `campaign_runs` or `campaign_review_feed` returned it. A run is one enrolled lead. NOT a feed row's `id` or `nodeRunId`.

kairon campaign set-graph

Replace the campaign's draft sequence graph

Full description

Replace the campaign's DRAFT sequence graph IN FULL — it overwrites, it is not a patch.

Flags: campaign set-graph
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--graph.nodes requiredjson array jsonEvery step in the sequence. Layout is automatic — send no coordinates.
--graph.edges requiredjson array jsonHow one step's outcome routes to the next — these are fixed rules, and a violation is refused. A node emits the outcomes in [brackets]; an edge carries exactly one of them, to one of the types after the arrow. A `*` outcome MUST route onward; any other may end the flow. A wait_connection_accepted needs a send_invite SOMEWHERE upstream — not necessarily right before it. Put a second one further down a `timeout` branch to re-ask whether they have accepted yet; two waits back to back are refused. A wait that leads to another wait on its `timeout` branch MUST set withdrawOnTimeout:false — the default takes the invite back, leaving the later wait nothing that can be accepted. send_invite [sent] → wait_connection_accepted wait_connection_accepted [timeout, accepted*] → delay, send_message, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, wait_reply, agentic_reply delay [default*] → send_invite, wait_connection_accepted, send_message, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, wait_reply, agentic_reply send_message [sent] → wait_connection_accepted, delay, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_email, audience_split, wait_reply, agentic_reply like_last_post [done] → send_invite, wait_connection_accepted, delay, send_message, visit_profile, follow_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, wait_reply, agentic_reply visit_profile [done] → send_invite, wait_connection_accepted, delay, send_message, like_last_post, follow_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, wait_reply, agentic_reply follow_profile [done] → send_invite, wait_connection_accepted, delay, send_message, like_last_post, visit_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, wait_reply, agentic_reply remove_relation [done] → send_invite, wait_connection_accepted, delay, like_last_post, visit_profile, follow_profile, comment_on_post, send_inmail, send_email, audience_split, wait_reply comment_on_post [commented] → send_invite, wait_connection_accepted, delay, send_message, like_last_post, visit_profile, follow_profile, remove_relation, send_inmail, send_email, audience_split, wait_reply, agentic_reply send_inmail [sent] → wait_connection_accepted, delay, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_email, audience_split, wait_reply, agentic_reply send_email [sent] → send_invite, wait_connection_accepted, delay, send_message, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_inmail, audience_split, wait_reply, agentic_reply audience_split [branch_a*, branch_b*] → send_invite, wait_connection_accepted, delay, send_message, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, wait_reply, agentic_reply wait_reply [timeout, replied] → send_invite, wait_connection_accepted, delay, send_message, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_inmail, send_email, audience_split, agentic_reply agentic_reply [no_reply, done] → wait_connection_accepted, delay, like_last_post, visit_profile, follow_profile, remove_relation, comment_on_post, send_email, audience_split PATH RULE (the rows cannot show this): after a wait's `timeout` outcome the lead is NOT connected, so NO send_message may follow it — a `delay` in between changes nothing. It stays banned down that branch until something says otherwise: a later gate's `accepted`, or a fresh accepted invite. Instead: nudge them with like_last_post / visit_profile / follow_profile / comment_on_post / send_inmail / send_email / audience_split / wait_reply / agentic_reply; re-ask with another wait_connection_accepted (the earlier wait then needs withdrawOnTimeout:false) and send off ITS `accepted`; send another invite and message off the new `accepted`. PATH RULE (the rows cannot show this): audience_split is SEE-THROUGH. It takes no time and sends nothing, so what may follow it is decided by the step BEFORE it, not by its own row above. A step you may not put directly after X you also may not put after a split that follows X.
--graph.startNodeKey requiredjson jsonThe `key` of the step each lead begins on. `null` lets it be inferred when exactly one node has no inbound edge; name it when the graph has several roots or loops back through every step, or publish fails with `no_start`.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "campaign-building" }) and of framework_get({ slug: "outreach" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon campaign stats

How the campaign is doing

Full description

How a campaign is performing, in one read — and the read before campaign_activate.

Flags: campaign stats
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--days json jsonWindow for the daily activity series, 7 or 30, in the campaign's own local days. OMIT IT and the series is left out entirely rather than defaulted — do not pay to read one you were not asked for.

kairon campaign template-get

Read one campaign template in full

Full description

One template, in the shapes the build tools take.

Flags: campaign template-get
FlagTypeWhat it is for
--id requiredreactivation|nurturing|inbound-engagers|competitor-engagers|company-page-engagers|keyword|travel|third-party-event|own-event|webinar|networking|lead-magnetWhich template — an `id` from `campaign_template_list`.
--locale en|esThe operator's language for names and messages: `en` (default) or `es`. Pick the one the operator writes in; Kairon translates a message per lead's language when it drafts.

kairon campaign template-list

List the campaign templates

Full description

The campaign templates the app's New campaign page offers: each an id, a name, what it is for, its kind and the signals its lead list needs.

Flags: campaign template-list
FlagTypeWhat it is for
--locale en|esThe operator's language for names and messages: `en` (default) or `es`. Pick the one the operator writes in; Kairon translates a message per lead's language when it drafts.

kairon campaign update

Edit the campaign's configuration and audience

Full description

Edit a campaign's configuration — any subset of its fields; omitted ones are unchanged.

Flags: campaign update
FlagTypeWhat it is for
--name stringThe campaign's name, for the operator to recognise it. Not seen by any lead.
--sendWindow.days json array jsonWeekdays sends may fire, 0 = Sunday to 6 = Saturday. At least one, no duplicates.
--sendWindow.startHour integerFirst hour sends may fire, 0-23, in `timeZone`. Must be before `endHour`.
--sendWindow.endHour integerLast hour sends may fire, 0-23, in `timeZone`. Must be after `startHour`.
--sendWindow.timeZone stringIANA zone the hours are read in, e.g. `America/Argentina/Buenos_Aires`. ASK the operator rather than assuming: a valid zone that is not theirs is accepted silently and sends at the wrong hour every day, with nothing to flag it.
--autonomy manual|autopilot`autopilot` (the default) fires each send on schedule. `manual` parks EVERY send for the operator to approve first, so a manual campaign looks active and sends nothing until someone works the queue.
--allowsReEntry booleanMay a person enter this campaign more than once? `false` (the default) means someone who finished it never comes back — the rule every campaign has always had. `true` lets them re-enter later, which is what a nurture campaign is for. It never permits two messages at once: one live run per person, always, whatever this says.
--sendFromOwner booleanWith several sending seats: send each lead from its OWNER's seat. `true` means a lead whose owner has a working seat in this campaign is contacted from that seat only (it waits for that seat's daily room); a lead with no owner, or whose owner's seat is disconnected, removed or gone, goes to whichever seat has room. `false` (the default) ignores owners: every seat takes the oldest leads. No effect with one seat.
--dailyEnrollmentLimit integerThe DEFAULT new leads per day, per sender, 1-200 (default 30): every sender without a limit of its own enrolls up to this many a day, so the campaign's day is the sum over its senders. Caps the START of new runs, not sends — the org's own per-seat limits still apply on top. Senders are added, removed and given their own limit with `campaign_seat_add` / `campaign_seat_remove` / `campaign_seat_update`.
--priority json jsonWhich campaign this LinkedIn account serves first when two of them are due on the same day. 0 is highest. Lower sorts first, matching every other priority in Kairon. `null` clears it — no priority, served after Low; omitted leaves it unchanged. It is an ORDER, never an allowance: it does not change how many leads any campaign enrols (`dailyEnrollmentLimit` does that), and it never moves a send that is already scheduled.
--endsOn json jsonThe day this campaign stops, `YYYY-MM-DD`, in its send window's time zone. On that day it pauses itself (reason `ended`) and nothing more goes out — no new leads, no follow-ups. Today counts: setting today or an earlier day on a running campaign pauses it AT ONCE, so to make today the last sending day, pass tomorrow. Use it for a campaign tied to a dated event. `null` clears it; omitted leaves it unchanged. To run it again after it ended, move the date later or clear it, then resume.
--enrollmentFilter.buckets json array jsonWhich contact-history buckets may enroll: `new` (no conversation either way, and nothing a Kairon campaign sent), `unanswered` (we messaged, no reply), `in_conversation` (they wrote to us). Unique, at least one. All three means enroll everyone. Anyone outside the selected buckets is skipped, not queued, so a narrow set is why a large audience enrolls almost nobody.
--enrollmentFilter.scope seat|orgWhose prior-contact history is read: `seat` (this campaign's sending seat) or `org` (every LinkedIn seat). Copying a `seat` filter onto a DIFFERENT seat changes what it means — the new seat's history is empty, so people the original filter excluded now enroll.
--icpId json jsonThe ICP that gates enrollment. `null` clears it (no ICP check); omitted leaves it unchanged. Must be an ICP in this org. Leads that fail it are marked Skipped, never messaged.
--stopOnReply booleanDefault `true` — a reply halts that person's run so nothing follows a real conversation. `false` keeps the sequence going after they answer; set it only when the operator asked.
--connectionDegree any|only_first|exclude_firstWhether the sender's existing LinkedIn connection matters. `any` (the default) ignores it. `only_first` enrolls ONLY people the sender is already connected to. `exclude_first` enrolls only people they are NOT connected to — the usual choice for cold outreach that opens with an invite. Anything but `any` costs one extra LinkedIn read per candidate, and skips the people it excludes rather than queueing them.
--stopOnCompanyReply off|any_reply|interestedWhether one person answering stops their colleagues. `off` (the default) works every lead on their own merits. `any_reply` stops the rest of a company once anyone there answers THIS campaign. `interested` stops it only when the answer was an interested one, so a colleague's "no thanks" leaves the others working. Colleagues are matched on their LinkedIn employer, so someone whose employer Kairon has never seen is never stopped by it. It stops people waiting to enter AND people already inside — but never someone who has written to you, whose conversation always continues.
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--leadListIds json array jsonLead lists to bind, ADDITIVELY. A list already bound stays bound, and a bound list you leave out is NOT unbound — omission cannot unbind, because that would cancel every in-flight run drawn from the list.
--initiativeId json jsonThe initiative this campaign serves. `null` detaches it; omitted leaves it unchanged. A campaign serves at most ONE initiative, so a different id MOVES it. Detaching changes nothing else — a campaign that outlives its initiative keeps sending.

kairon campaign version-restore

Bring an earlier sequence graph back as the draft

Full description

Copy an earlier published version back into the campaign's editable DRAFT, steps and routing and layout intact — the way to undo an edit that replaced copy someone wrote.

Flags: campaign version-restore
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--versionNumber requiredintegerThe version to bring back, as `campaign_versions` listed it.

kairon campaign versions

Read the campaign's earlier sequence graphs

Full description

Every version this campaign has published, newest first, plus its unpublished draft — with a line per version saying what it changed (steps added/removed/edited, routing).

Flags: campaign versions
FlagTypeWhat it is for
--id requiredstringThe campaign id, as `campaign_list` or `campaign_create` returned it.
--versionNumber integerOmit for the list of versions. Give one to get THAT version’s full graph, in exactly the shape `campaign_set_graph` accepts.

kairon chat

kairon chat list

List conversations

Full description

List conversations, newest activity first, across every channel that holds them.

Flags: chat list
FlagTypeWhat it is for
--seatId stringOne teammate's seat id, from `seat_list`. Defaults to your own.
--scope mine|org'mine' (default) is your own seat; 'org' is every seat in the organization.
--unread booleanTrue returns only chats with unread messages.
--answered yes|no'no' returns chats waiting on a reply from you (they spoke last); 'yes' returns the ones you already answered. Chats whose history has not been loaded yet match neither.
--leadsOnly booleanOnly chats already linked to a lead.
--needsHuman booleanOnly chats where Kairon handed the conversation back and is waiting on you.
--classification interested|objection|neutral|not_interestedWhat their last inbound message meant — not a Pipeline stage. Combine with answered: "no" for interested replies you have not answered.
--seen booleanTrue returns LinkedIn chats where they saw your last message and have not replied. Checks LinkedIn live for up to 50 chats first, so the first call can take up to a minute; calling again works through the rest. On normal (non-Sales Navigator) chats many people hide read receipts, so a chat missing here may still have been read. It already means your message is the last one: do not combine it with answered.
--q stringCase-insensitive match on the counterpart's NAME.
--cursor string
--limit integer

kairon chat messages

Read a conversation

Full description

Read one conversation's messages, newest first, by the chatId from chat_list — LinkedIn or email.

Flags: chat messages
FlagTypeWhat it is for
--chatId requiredstring
--cursor string
--limit integer

kairon checkpoint

kairon checkpoint delete

Withdraw a checkpoint

Full description

Remove one checkpoint from an initiative’s history.

Flags: checkpoint delete
FlagTypeWhat it is for
--initiativeId requiredstringThe initiative the checkpoint belongs to.
--checkpointId requiredstringThe checkpoint id (`ckpt_…`), as `initiative_get` returned it in the history.

kairon checkpoint edit

Correct a checkpoint

Full description

Fix what one checkpoint says, or the verdict it froze — for a typo or a verdict typed by mistake.

Flags: checkpoint edit
FlagTypeWhat it is for
--body stringWhat happened and the ONE thing to do next, in markdown. Say the numbers you read and how they compare to this org’s own baseline, and whether the last checkpoint’s recommendation was actually done. To put a teammate’s name on a next step, mention them: `[@Ana](#kairon-ana@co.com)` — a normal markdown link whose destination is `#kairon-` plus their user id, email, or name (spaces as `+`). Whichever you use is stored as their id, and a name nobody here matches, or one two teammates share, is refused rather than saved as prose. Read user ids and names off `seat_list`.
--health on_track|at_risk|off_trackThe verdict, frozen at publish: `on_track`, `at_risk` or `off_track`. Judge VOLUME before rates — a low number of sends is not a bad result, it is not a result yet.
--initiativeId requiredstringThe initiative the checkpoint belongs to.
--checkpointId requiredstringThe checkpoint id (`ckpt_…`), as `initiative_get` returned it in the history.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "gtm-checkpoint" }) and of framework_get({ slug: "loop" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon checkpoint publish

Publish a checkpoint on an initiative

Full description

Record a dated verdict on an initiative: what happened, the one thing to do next, and a health of on_track, at_risk or off_track.

Flags: checkpoint publish
FlagTypeWhat it is for
--body requiredstringWhat happened and the ONE thing to do next, in markdown. Say the numbers you read and how they compare to this org’s own baseline, and whether the last checkpoint’s recommendation was actually done. To put a teammate’s name on a next step, mention them: `[@Ana](#kairon-ana@co.com)` — a normal markdown link whose destination is `#kairon-` plus their user id, email, or name (spaces as `+`). Whichever you use is stored as their id, and a name nobody here matches, or one two teammates share, is refused rather than saved as prose. Read user ids and names off `seat_list`.
--health requiredon_track|at_risk|off_trackThe verdict, frozen at publish: `on_track`, `at_risk` or `off_track`. Judge VOLUME before rates — a low number of sends is not a bad result, it is not a result yet.
--initiativeId requiredstringThe initiative being judged (`init_…`).
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "gtm-checkpoint" }) and of framework_get({ slug: "loop" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon company

kairon company followers

List a company page’s followers

Full description

The people who follow a LinkedIn company page YOUR seat administers — the second opted-in audience after a newsletter, and often the bigger one.

Flags: company followers
FlagTypeWhat it is for
--target requiredjson jsonThe company page whose followers to read — named by URL, universal name, or provider id. It must be a page this seat ADMINISTERS; LinkedIn shows followers to admins only.
--cursor stringContinue from a previous page. Omit for the first page.
--count integerFollowers per page (default 50, the most LinkedIn allows for a page).
--intoList stringAppend this page’s followers to one of your lead lists, by name or id. Combine with `exhaust` to walk the whole audience into it.
--exhaust booleanPage server-side until the results run out, instead of returning a cursor for you to send back. Requires `intoList`: every page is appended there and NO hits come back, only the totals — which is the point, since neither the hits nor the cursor then cross your context. Stops at `maxResults` and hands back a `cursor` to resume from. Each page still costs one metered action.
--maxResults integerHow many hits an `exhaust` run collects before it stops (default 500, max 2000). Ignored without `exhaust`. Raise it when you know the audience is large and you mean to spend the actions.
--readReceipts json jsonRequired with `intoList`: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon company posts

A company page's recent posts

Full description

A page of a COMPANY page's own posts — what a competitor, a partner or a target account publishes under its own name, not what its people post.

Flags: company posts
FlagTypeWhat it is for
--target requiredjson jsonThe company page whose posts to read — named by URL, universal name, or provider id.
--cursor string

kairon config

kairon config get

Read the operator's own material

Full description

What the operator has told Kairon: their competitor and source URLs, and their organization's value proposition, lead magnet and learnings log.

Flags: config get
FlagTypeWhat it is for
--sections json array jsonWhich sections to read. Omit for all five.

kairon config set

Save the operator's own material

Full description

Replace one or more sections of what the operator has told Kairon: competitorUrls, sourceUrls, valueProposition, leadMagnet, learnings.

Flags: config set
FlagTypeWhat it is for
--competitorUrls json array jsonReplaces every competitor URL. Each must be a LinkedIn URL.
--sourceUrls json array jsonReplaces every source URL. Any http(s) URL.
--valueProposition stringReplaces the organization's value proposition. An empty string clears it.
--leadMagnet stringReplaces the organization's lead magnet — what it gives a prospect to earn a reply. An empty string clears it.
--learnings stringReplaces the organization's GTM learnings log WHOLE. To append an entry, read the log first and write back the joined text. An empty string clears it.

kairon crm

kairon crm push

Send leads to the organization's CRM

Full description

Sends these leads to the CRM the organization connected (HubSpot or Salesforce), whatever their Pipeline stage.

Flags: crm push
FlagTypeWhat it is for
--leadIds requiredjson array jsonThe leads to send (lead ids, `lead_…`), at most 1000.

kairon doc

kairon doc get

Read one product doc

Full description

One product doc in full, as markdown, by a slug from doc_list.

Flags: doc get
FlagTypeWhat it is for
--slug requiredstringWhich doc to read — a `slug` from `doc_list`, e.g. "campaigns".

kairon email

kairon email domain-buy

Buy the sending domain

Full description

Order a sending domain and its mailboxes.

Flags: email domain-buy
FlagTypeWhat it is for
--domain requiredstringThe domain name to buy and send from, like `acme-outreach.com`. Only `.com` and `.org` can be registered, and a name carrying a well-known trademark is refused. Not the customer's real website — a sending domain is a separate name, so a problem with it never touches their main domain's reputation.
--mailboxes requiredjson array jsonThe mailboxes to create on the domain — one to five, each a real person on the team, since a recipient who replies is replying to that name. More mailboxes means more sending capacity and more monthly cost.
--forwardingDomain stringThe customer's real website, where a visitor to the sending domain is sent — `acme.com`. Worth setting: a sending domain that resolves to nothing is exactly what a suspicious recipient checks. Any extension, not just .com/.org. Ask the operator; never guess it from their email address.
--agreedTotal requirednumberThe `dueNow` from the quote the operator agreed to, in whole dollars. The order is re-priced against the vendor immediately before buying and refused if the number moved, so a stale quote can never charge a different amount than the one shown.

kairon email domain-check

Check a sending domain’s DNS records

Full description

Ask Instantly whether this domain's MX, SPF, DKIM and DMARC records are set up correctly.

Flags: email domain-check
FlagTypeWhat it is for
--domain requiredstringA sending domain this workspace already has — read them from `email_setup_get`. Not any domain: this must be one Kairon sends from for this org.

kairon email domain-quote

What would this sending domain cost?

Full description

Price a sending domain and its mailboxes.

Flags: email domain-quote
FlagTypeWhat it is for
--domain requiredstringThe domain name to buy and send from, like `acme-outreach.com`. Only `.com` and `.org` can be registered, and a name carrying a well-known trademark is refused. Not the customer's real website — a sending domain is a separate name, so a problem with it never touches their main domain's reputation.
--mailboxes requiredjson array jsonThe mailboxes to create on the domain — one to five, each a real person on the team, since a recipient who replies is replying to that name. More mailboxes means more sending capacity and more monthly cost.
--forwardingDomain stringThe customer's real website, where a visitor to the sending domain is sent — `acme.com`. Worth setting: a sending domain that resolves to nothing is exactly what a suspicious recipient checks. Any extension, not just .com/.org. Ask the operator; never guess it from their email address.

kairon email format-set

Send email as plain text or HTML

Full description

Switch how the managed email campaign sends: text (plain text, the default) or html (formatted).

Flags: email format-set
FlagTypeWhat it is for
--format requiredtext|html`text` sends plain text (the default). `html` sends formatted email, so mailbox signatures may use HTML — links, bold, a logo. It applies to every email the managed campaign sends. Switching back to `text` is refused while a mailbox signature still has HTML in it.

kairon email mailbox-add

Add a mailbox the customer already owns

Full description

Add a mailbox the customer ALREADY owns — on their own domain, in their own Google Workspace or Microsoft account — so Kairon can send from it.

Flags: email mailbox-add
FlagTypeWhat it is for
--email requiredstringThe full address of a mailbox the customer already owns, like `ada@acme.com`.
--firstName requiredstringThe mailbox owner's first name — it appears in the From line of every send.
--lastName requiredstringThe mailbox owner's last name.
--provider requiredgoogle|microsoft|customWho hosts the mailbox. `google` for Google Workspace or Gmail, `microsoft` for Microsoft 365 or Outlook — both fill in their own server settings. `custom` for anything else, and then all four host and port fields are required.
--password requiredstringAn APP PASSWORD for the mailbox, not the account password. For Google the operator creates one in their Google account with 2-step verification on. Ask them for it directly and never invent one; it is passed straight to the sending provider and stored nowhere in Kairon.
--smtpHost stringOutgoing mail server, `custom` provider only (Google and Microsoft are known).
--smtpPort integerOutgoing mail port, `custom` provider only — usually 465 or 587.
--imapHost stringIncoming mail server, `custom` provider only.
--imapPort integerIncoming mail port, `custom` provider only — usually 993.

kairon email mailbox-limit-set

Set a mailbox’s daily sending limit

Full description

Set how many campaign emails one mailbox may send per day, from 1 to 30 (Instantly’s own recommendation for a cold mailbox).

Flags: email mailbox-limit-set
FlagTypeWhat it is for
--email requiredstringThe mailbox, as `email_setup_get` lists it under its domain.
--dailyLimit requiredintegerCampaign emails this mailbox may send per day, 1 to 30. Some mailboxes allow fewer — `email_setup_get` names each one's `dailyLimitMax`. Warmup email does not count against it.

kairon email mailbox-signature-set

Set a mailbox’s email signature

Full description

Set the signature under every campaign email one mailbox sends — up to 1000 characters, line breaks kept; an empty string removes it.

Flags: email mailbox-signature-set
FlagTypeWhat it is for
--email requiredstringThe mailbox, as `email_setup_get` lists it under its domain.
--signature requiredstringThe text Instantly puts under every campaign email this mailbox sends — a name, a role, a phone. Line breaks are kept. Empty removes it. No `{{ }}` variables. HTML only when `email_setup_get` says `emailFormat: "html"` (switch it with `email_format_set`); in plain-text sending it is refused.

kairon email setup-get

Read the email sending setup

Full description

How this workspace sends email: emailProvider first — instantly, unipile (each person sends from their own Gmail/Outlook mailbox, connected by that person in Settings > Integrations > Email; there is nothing to buy or warm up), or null (no…

Takes no flags.

kairon email warmup-start

Start warmup on a domain’s mailboxes

Full description

Start warming up every mailbox on this sending domain.

Flags: email warmup-start
FlagTypeWhat it is for
--domain requiredstringA sending domain this workspace already has — read them from `email_setup_get`. Not any domain: this must be one Kairon sends from for this org.

kairon exclusion

kairon exclusion add

Forbid contact with people or companies

Full description

Forbid contact with 1..1000 people or companies.

Flags: exclusion add
FlagTypeWhat it is for
--facet requiredpeople|companiesWhat these items are. `people` suppresses each named individual. `companies` suppresses the company itself AND everyone who works there.
--items requiredjson array jsonThe entries to add, up to 20000. Each is judged on its own, so one invalid item never fails the rest.

kairon exclusion list

Read the organization's exclusion list

Full description

Who this organization must never contact — the org-wide suppression list, in two facets: people (named individuals) and companies (the company itself AND everyone who works there).

Flags: exclusion list
FlagTypeWhat it is for
--facet people|companiesRead one facet only. Omit to get both, which is what "is this person blocked?" needs — someone can be suppressed by their employer's entry rather than by their own.

kairon exclusion remove

Remove one entry from the exclusion list

Full description

Stop suppressing one person or one company, by the entry id exclusion_list returned (exper_… on people, excom_… on companies).

Flags: exclusion remove
FlagTypeWhat it is for
--facet requiredpeople|companiesWhich facet the entry sits on. It decides the id prefix: `people` → `exper_…`, `companies` → `excom_…`.
--id requiredstringThe entry id, exactly as `exclusion_list` returned it.

kairon feedback

kairon feedback report

Report a problem back to Kairon

Full description

Tell Kairon that something went wrong for this user.

Flags: feedback report
FlagTypeWhat it is for
--problem requiredstringWhat the user was trying to do, and what went wrong, in your own words. Concrete beats polite: name the entity, the filter, the campaign, whatever they were actually working on.
--priority requiredurgent|high|medium|lowHow far up the queue this goes. Read these in order and stop at the FIRST one that fits — do not weigh them against each other. `urgent` — something wrong already left Kairon and cannot be taken back: a message sent to the wrong person or with broken text, a person contacted despite an exclusion, a wrong value written that the user has not seen. `high` — the user cannot finish what they came to do, and you found no way around it. `medium` — they finished, but only through a workaround, a retry, or repairing something by hand. `low` — they finished as intended; it cost extra turns, a confusing answer, or a limit nobody documented. Two tie-breakers: when two rungs both fit, send the LOWER one, and a mistake the user never saw is never `urgent`.
--tools json array jsonThe Kairon tools involved, in the order you called them. Include a tool that returned no error but the wrong answer — that case is the reason this field is not just an error string.
--quote stringThe user's own words, when they explain the problem better than your summary. Their exact phrasing, no more than a sentence or two. Omit it rather than paraphrase — a paraphrase here is just your summary twice.

kairon filter

kairon filter resolve

Resolve a Sales Navigator filter

Full description

Resolve a human-readable Sales Navigator filter value (location, industry, function) to a LinkedIn id, echoing the canonical label so a wrong match is visible.

Flags: filter resolve
FlagTypeWhat it is for
--type requiredlocation|industry|function|current_company|past_company|company_location|school|past_role|groups|persona|technologies|account_lists|lead_lists|postal_codeWhich Sales Navigator dimension the name belongs to.
--query requiredstringThe human-readable NAME to resolve, e.g. "San Francisco Bay Area". Never a LinkedIn id — resolving one is what this is for, and the canonical label comes back so a wrong match is visible.

kairon framework

kairon framework get

Read go-to-market axioms

Full description

Axioms in full, as markdown — ONE by slug from framework_list, or a whole area at once (every axiom in it, in order).

Flags: framework get
FlagTypeWhat it is for
--slug stringWhich axiom to read — a `slug` from `framework_list`. An area name reads the whole area, like `area`.
--area belief-system|targeting|outreach|content|loopRead every axiom of one area at once instead of one by `slug`.

kairon framework list

List the go-to-market axioms

Full description

Kairon's go-to-market theory: the standalone truths every playbook rests on, each a slug, an area (belief-system, targeting, outreach, content, loop) and a title that says exactly what is inside.

Takes no flags.

kairon group

kairon group members

List a LinkedIn group’s members

Full description

The members of a LinkedIn group, from the group’s own member list — people who joined a community around a topic, which is a targeting fact no search filter can express.

Flags: group members
FlagTypeWhat it is for
--group requiredstringThe group, as its URL (https://www.linkedin.com/groups/<id>/) or its bare numeric id. Read on your own seat: a public group needs no membership and no Sales Navigator; a members-only group needs your seat to have joined it.
--cursor stringContinue from a previous page. Omit for the first page.
--count integerMembers per page (default 50, max 100). LinkedIn refuses anything higher.
--intoList stringAppend this page’s members to one of your lead lists, by name or id. Combine with `exhaust` to walk the group into it without any of it crossing your context.
--exhaust booleanPage server-side until the results run out, instead of returning a cursor for you to send back. Requires `intoList`: every page is appended there and NO hits come back, only the totals — which is the point, since neither the hits nor the cursor then cross your context. Stops at `maxResults` and hands back a `cursor` to resume from. Each page still costs one metered action.
--maxResults integerHow many hits an `exhaust` run collects before it stops (default 500, max 2000). Ignored without `exhaust`. Raise it when you know the audience is large and you mean to spend the actions.
--readReceipts json jsonRequired with `intoList`: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon icp

kairon icp create

Create an ICP

Full description

Create an ICP — a target thesis spanning the companies to reach and the people inside them — as an UNPUBLISHED DRAFT: nothing can qualify against it, and no list or campaign can pick it, until icp_publish makes it version 1.

Flags: icp create
FlagTypeWhat it is for
--name requiredstringA short, specific name — the segment, not the pitch.
--definition.description json jsonThe targeting thesis in prose: who these companies and people are, the pains they carry, and the observable signals that say one needs this NOW. Not sent to Sales Navigator and not judged as a check.
--definition.companySalesNavCriteria json json
--definition.peopleSalesNavCriteria json json
--definition.companyQualificationConditions json array jsonJudges the COMPANY. Rules: see `definition`.
--definition.strictFilters boolean
--definition.waiveMissingCompany boolean
--definition.peopleQualificationConditions json array jsonJudges the PERSON. Rules: see `definition`.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "icp-definition" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon icp criteria-list-edit

Add or remove values in one ICP filter list

Full description

Add or remove values inside ONE filter list of one criteria side of the ICP's DRAFT, carrying the whole rest of the ICP forward.

Flags: icp criteria-list-edit
FlagTypeWhat it is for
--icpId requiredstring
--side requiredcompany|peopleWhich criteria side to edit: the company search or the people search.
--list requiredrole.include|role.exclude|seniority.include|seniority.exclude|companyHeadcount|filters|headcountWhich list inside that side. People: `role.include`, `role.exclude`, `seniority.include`, `seniority.exclude`, `companyHeadcount`, `filters`. Company: `headcount`, `filters`. A list the side does not have is refused by name.
--add json array jsonValues to append. Strings for every list but `filters`, which takes `{ type, query, mode? }`. A value already there is left alone, never duplicated.
--remove json array jsonValues to drop, matched exactly (a `filters` item on type + query + mode). A value that is not there is reported back, not an error.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "icp-definition" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon icp get

Get an ICP

Full description

Read one ICP by icpId: its status, its live version (what everything qualifies against; null until the first publish), its draft (unpublished edits; null when there are none) and changes — what publishing the draft would change.

Flags: icp get
FlagTypeWhat it is for
--icpId requiredstring

kairon icp publish

Publish an ICP's draft

Full description

Make the ICP's draft its next live version.

Flags: icp publish
FlagTypeWhat it is for
--icpId requiredstring
--ifDraftUpdatedAt stringThe `draft.updatedAt` you showed the operator. Publish then refuses (ICP_DRAFT_CHANGED) if the draft changed after, instead of publishing edits they did not see.

kairon icp update

Update an ICP

Full description

Edit an ICP's DRAFT.

Flags: icp update
FlagTypeWhat it is for
--icpId requiredstring
--name stringA short, specific name — the segment, not the pitch.
--definition.description json jsonThe targeting thesis in prose: who these companies and people are, the pains they carry, and the observable signals that say one needs this NOW. Not sent to Sales Navigator and not judged as a check.
--definition.companySalesNavCriteria json json
--definition.peopleSalesNavCriteria json json
--definition.companyQualificationConditions json array jsonJudges the COMPANY. Rules: see `definition`.
--definition.strictFilters boolean
--definition.waiveMissingCompany boolean
--definition.peopleQualificationConditions json array jsonJudges the PERSON. Rules: see `definition`.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "icp-definition" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon icp version-restore

Bring an earlier ICP definition back into the draft

Full description

Copy an earlier published version into the ICP's DRAFT — exactly like a campaign restore.

Flags: icp version-restore
FlagTypeWhat it is for
--icpId requiredstring
--version requiredintegerThe version to bring back, as `icp_versions` listed it.

kairon icp versions

Read an ICP's earlier definitions

Full description

Every PUBLISHED version of this ICP, newest first, with the date, the check counts and changes against the version before — and which one is in use.

Flags: icp versions
FlagTypeWhat it is for
--icpId requiredstring
--version integerOmit for the list of versions. Give one to get THAT version in full.

kairon identity

kairon identity get

Who you are acting as

Full description

Who this connection acts as: the user, their organization, the seat (seatId plus its state: connected, none, or locked — needs a subscription), linkedin, and capabilities.

Takes no flags.

kairon impersonate

kairon impersonate list

List who you can act as

Full description

The users you may act as, each with their organization and whether they have a LinkedIn account connected — you can only act as someone who does.

Flags: impersonate list
FlagTypeWhat it is for
--search stringFilter by name, email address or organization name.

kairon impersonate start

Act as another user

Full description

Act as another user from now on: every later call runs as them, on their LinkedIn seat and their organization.

Flags: impersonate start
FlagTypeWhat it is for
--user requiredstringThe email address or user id to act as.

kairon initiative

kairon initiative delete

Withdraw a go-to-market initiative

Full description

Remove one initiative from the board.

Flags: initiative delete
FlagTypeWhat it is for
--initiativeId requiredstringThe initiative to remove, by id (`init_…`).

kairon initiative get

Read one go-to-market initiative

Full description

One initiative whole: the thinking in its body, the campaigns serving it as the campaigns list knows them, and every checkpoint newest-first with the verdict each one froze.

Flags: initiative get
FlagTypeWhat it is for
--initiativeId requiredstringThe initiative to read, by id (`init_…`).

kairon initiative list

List the go-to-market initiatives

Full description

Every initiative in the organization: what it tries, its status, the health of its latest checkpoint and how many days old that verdict is, plus the summed funnel of the campaigns serving it.

Flags: initiative list
FlagTypeWhat it is for
--status draft|active|completed|canceledReturn only initiatives in this state. Omit for all of them, including completed and canceled ones.

kairon initiative set

Create or edit a go-to-market initiative

Full description

Write down an initiative: a name, the thinking in markdown, and who is accountable for it.

Flags: initiative set
FlagTypeWhat it is for
--name stringShort, scannable name for the bet — "Expansión Centroamérica". REQUIRED when creating (no `initiativeId`); optional when editing. A create without one is refused rather than defaulted.
--body json jsonThe thinking, in markdown: what it tries, why, what would prove it worked, and what has been learned. Free-form on purpose — write what an operator would want to reread in three weeks. Put a teammate on a step by mentioning them: `[@Ana](#kairon-ana@co.com)`, a normal markdown link whose destination is `#kairon-` plus their user id, email, or name (spaces as `+`). It is stored as their id; a name nobody here matches, or one two teammates share, is refused. `seat_list` names them.
--status draft|active|completed|canceled`draft` while it is being shaped, `active` once it is being worked.
--priority json json0 is highest. Lower sorts first, matching every other priority in Kairon.
--startDate json json`YYYY-MM-DD`, this century. An initiative starts on a date, not at a moment.
--endDate json json`YYYY-MM-DD`, this century. When the initiative should have paid off, or be called. Must not be before `startDate`.
--initiativeId stringOmit to create a new initiative. Pass an id (`init_…`) to edit that one. Call `initiative_list` FIRST and reuse the id of any bet that already covers this — omitting it a second time creates a duplicate, it does not update.
--owner json jsonWho is accountable for this bet — one org member, by `email` (what you usually have) or `userId`. `null` leaves it unassigned; omit to leave it as it is.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "gtm-initiative" }) and of framework_get({ slug: "belief-system" }) and of framework_get({ slug: "loop" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon inmail

kairon inmail send

Send an InMail

Full description

Send an InMail (optional subject) to the person target addresses.

Flags: inmail send
FlagTypeWhat it is for
--target requiredjson jsonWho this acts on — one LinkedIn person or company, named by URL, vanity slug, or provider id.
--subject stringThe InMail subject line — the one thing that decides whether it is opened.
--text requiredstringThe InMail body, as it will be sent. Over MCP, em dashes and curly quotes become plain punctuation; nothing else rewrites it.
--attachments json array json
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "write-messages" }) and of framework_get({ slug: "outreach" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon insights

kairon insights report

How the whole account is performing

Full description

The org-wide outreach funnel over a date window — invites sent → accepted → messages → replied → interested — with the daily activity series and a per-seat breakdown, each seat carrying its campaigns and their acceptance, reply and interes…

Flags: insights report
FlagTypeWhat it is for
--from requiredstringFirst day of the window, `YYYY-MM-DD`, inclusive.
--to requiredstringLast day of the window, `YYYY-MM-DD`, inclusive. Must be on or after `from`, and the window must not exceed 366 days.
--userId stringNarrow to one seat owner. Omit for every seat in the organization.

kairon invitations

kairon invitations received

Pending connection requests

Full description

The connection requests waiting in your LinkedIn inbox — people who asked to connect with YOU and have not been answered.

Flags: invitations received
FlagTypeWhat it is for
--cursor stringContinue from a previous page. Omit for the first page.
--count integerInvitations per page (default 50, max 100).
--intoList stringAppend the people who invited you to one of your lead lists, by name or id. Combine with `exhaust` to walk every pending request into it.
--exhaust booleanPage server-side until the results run out, instead of returning a cursor for you to send back. Requires `intoList`: every page is appended there and NO hits come back, only the totals — which is the point, since neither the hits nor the cursor then cross your context. Stops at `maxResults` and hands back a `cursor` to resume from. Each page still costs one metered action.
--maxResults integerHow many hits an `exhaust` run collects before it stops (default 500, max 2000). Ignored without `exhaust`. Raise it when you know the audience is large and you mean to spend the actions.
--readReceipts json jsonRequired with `intoList`: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon invite

kairon invite send

Send a connection invitation

Full description

Send a LinkedIn connection invitation (optional note) through the caller's account.

Flags: invite send
FlagTypeWhat it is for
--target requiredjson jsonWho this acts on — one LinkedIn person or company, named by URL, vanity slug, or provider id.
--note stringThe connection-request note, up to 300 characters. Omit it entirely for a note-less invite, which is valid and often accepts better.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "write-messages" }) and of framework_get({ slug: "outreach" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon job

kairon lead

kairon lead email-set

Record what a finder learned about people's email addresses

Full description

Store the work email a finder returned, on the PEOPLE themselves — which is what an email campaign reads, unlike a custom list column.

Flags: lead email-set
FlagTypeWhat it is for
--items requiredjson array jsonWhat was learned about each person, each naming its subject by ONE of `memberId`, `url`, or `providerId`, plus either an `email` or `notFound: true`.
--source requiredclay|apollo|contactout|hunter|instantlyWhich finder produced these answers. Recorded per lead, so a bounce can later be traced to the provider that supplied the address. A human typing an address in does not use this tool.

kairon lead enrich

Find people's work emails and mobile phones

Full description

Find the work email and/or mobile of up to 100 people and save each find on the person, where campaigns read it.

Flags: lead enrich
FlagTypeWhat it is for
--items requiredjson array jsonThe people to search for, each named by ONE of `memberId`, `url`, or `providerId`.
--email booleanFind their work email.
--phone booleanFind their mobile phone.

kairon lead phone-set

Record what a finder learned about people's phone numbers

Full description

Store the phone a finder returned, on the PEOPLE themselves — where the operator sees it, in the list's Phone column and the person's card — unlike a custom list column, which is per list.

Flags: lead phone-set
FlagTypeWhat it is for
--items requiredjson array jsonWhat was learned about each person, each naming its subject by ONE of `memberId`, `url`, or `providerId`, plus either a `phone` or `notFound: true`.
--source requiredclay|apollo|contactoutWhich finder produced these answers. Recorded per lead, so a wrong number can later be traced to the provider that supplied it. A human typing a number in does not use this tool.

kairon linkedin

kairon linkedin fetch

Fetch a LinkedIn profile or company

Full description

Fetch a LinkedIn person OR company — whichever the target addresses ({ type, value }: url, public_identifier, or provider_id).

Flags: linkedin fetch
FlagTypeWhat it is for
--target requiredjson jsonWho this acts on — one LinkedIn person or company, named by URL, vanity slug, or provider id.
--kind profile|companyOverride auto-detection. Required for a company addressed by universal name or numeric id.
--refresh booleanTrue bypasses the cache and forces a live read from LinkedIn. Slower, and it spends a lookup against your headroom.
--withRecommendations booleanTrue also returns who recommended this person (and who they recommended), with each recommender identified. Warm-intro paths. Always spends a live lookup — never served from cache.
--relationship booleanProfile-only. True reads LIVE on YOUR own account, the only way to get the person's network distance and, for a 1st-degree connection, their contact panel. Without it the read may run on Kairon's shared capacity, where those come back empty.

kairon list

kairon list add

Add members to a list

Full description

Add members to a list ({ asset, id, items }, up to 500).

Flags: list add
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--items requiredjson array jsonThe rows to add, each naming its subject by ONE of `memberId`, `url`, `providerId`, or `snapshot`.

kairon list archive

Archive or restore a list

Full description

Archive (archived: true) or restore (archived: false) a list by asset + id.

Flags: list archive
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--archived requiredbooleantrue archives the list; false restores it.

kairon list create

Create a list

Full description

Create a named list — the campaign targeting unit.

Flags: list create
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--name requiredstringThe list's name, for the operator to recognise it.
--audience.include.match all|anyHow this group's conditions join. `all` means a lead must satisfy EVERY condition; `any` means one is enough. Inside a single condition the fields always AND and the values in a field always OR, whatever `match` says — so `{ crmStage: ['on_hold','lost'], tagId: ['t1'] }` reads as (on_hold OR lost) AND t1.
--audience.include.conditions json array jsonThe conditions this group joins, 1 to 10. Each must name at least one field; an empty condition is refused rather than read as 'everyone'.
--audience.exclude.match all|anyHow this group's conditions join. `all` means a lead must satisfy EVERY condition; `any` means one is enough. Inside a single condition the fields always AND and the values in a field always OR, whatever `match` says — so `{ crmStage: ['on_hold','lost'], tagId: ['t1'] }` reads as (on_hold OR lost) AND t1.
--audience.exclude.conditions json array jsonThe conditions this group joins, 1 to 10. Each must name at least one field; an empty condition is refused rather than read as 'everyone'.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon list delete

Delete a list

Full description

Soft-delete a list by asset + id: it disappears from list_list with its memberships, the member leads/companies are untouched (they stay in the org pool, in their other lists, with their qualification state intact), and the name is immedia…

Flags: list delete
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring

kairon list get

Get one list

Full description

One list by asset + id: its name, live member count, created date, and its ordered columns (the list's own custom columns — free-text fields you attach to its members).

Flags: list get
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring

kairon list list

List lists

Full description

Read this org's lists of one asset, keyset-paginated, newest first, each with its live member count.

Flags: list list
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--q stringCase-insensitive substring of the list's name.
--cursor string
--limit integer
--archived booleanfalse (default) lists the active lists only. true lists ONLY the archived ones — archived lists never appear in the default view.

kairon list members

Read a list's members

Full description

One keyset page of a list's members.

Flags: list members
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--q stringCase-insensitive substring over the member's display fields.
--cursor string
--limit integer
--tags json array jsonKeep only members carrying EVERY tag named — an AND, not an OR. Matched case-insensitively; a name no tag has yields an empty page rather than an error.
--sort person|title|company|email|phone|industry|qualification|owner|added|sourceWhich column to order by. Leads: person, title, company, email, phone, qualification, owner, added, source. Companies: company, industry, qualification, owner, added. Naming a field the asset does not have is refused. Omit for the default, newest-added first.
--direction asc|descOrder direction; read as `asc` once a `sort` field is named.
--qualificationStatus json jsonKeep members whose ICP verdict is ANY OF these: qualified, disqualified, unevaluated. `unevaluated` means nobody has judged them — never that they failed.
--ownerId json jsonKeep members owned by ANY OF these user ids. Ownership rides the entity, not the list.
--tagId json jsonKeep members carrying ANY OF these tag ids — an OR, and the counterpart to `tags` above, which is an AND over NAMES.
--addedAfter stringKeep members added to THIS list at or after this ISO timestamp.
--addedBefore stringKeep members added to THIS list strictly before this ISO timestamp.
--hydrated booleantrue keeps members whose LinkedIn facts have been loaded; false keeps the ones nobody has fetched yet (they have no size or HQ to filter on).
--column json array jsonKeep members matching EVERY predicate over this list's custom columns. A name the list does not have is refused, so a typo cannot read as 'no matches'.
--includeQualification booleanAttach each member's stored qualification scorecard — the same body `qualification_get` returns, so a half-rejected list explains itself in ONE call instead of one per member. This is how you answer 'why were these disqualified'. Works on both assets. Off by default because it is BIG — every criterion with its rationale and evidence — so pair it with a small `limit` (10-25) rather than a full page.
--signalKey json jsonLeads only. Keep members that arrived from ANY OF these signals.
--crmStage json array jsonLeads only. Keep members standing at ANY OF these pipeline stages.
--emailState has|missing|unaskedLeads only. Narrow by what is known about the person's work email: `has` (an address is on file), `missing` (a finder was already asked and came back empty — asking again costs money and learns nothing), or `unasked` (nobody has looked). `unasked` is the one an enrichment pass wants: it IS the remaining work, so a pass can stop, resume tomorrow, and never pay twice for the same person.
--phoneState has|missing|unaskedLeads only. The same three states for the person's phone: `has`, `missing` (a finder already came back empty), `unasked` (nobody has looked — the worklist for a `lead_phone_set` pass).
--employeeMin integerCompanies only. Keep companies with AT LEAST this many employees.
--employeeMax integerCompanies only. Keep companies with AT MOST this many employees.
--industry json array jsonCompanies only. Keep companies carrying ANY OF these industries, matched case-insensitively against the whole industry list, not just the one shown as `subtitle`.
--hqCountry json array jsonCompanies only. Keep companies whose HQ is in ANY OF these ISO-2 country codes.

kairon list qualify

Qualify a list against an ICP

Full description

Judge a list's members against an ICP, in batches Kairon sizes: 20, then 40, then 80, then the rest of the list; an ICP edit starts again at 20.

Flags: list qualify
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--icpId requiredstringThe ICP to judge against. Its ACTIVE version is pinned when the run starts.
--subjectIds json array jsonThe members to judge. Omit for the next batch of the list. Ids that are no longer members, or past the batch limit, come back in `dropped`; `total` counts the rest.
--sample integerMake the next batch smaller than the limit — Kairon picks members with no verdict against this ICP version, at random. Ignored when `subjectIds` is given.
--ignoreIcpMismatch booleanHas no effect today: a run no longer stops because the list fits the ICP badly — it judges every member. Kept so older callers that pass it are not refused.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "list-building" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon list qualify-cancel

Stop a qualification run

Full description

Stop a run that is still going.

Flags: list qualify-cancel
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--runId requiredstringThe run to stop.

kairon list qualify-runs

Read a list's qualification run

Full description

How a run is going, or how it ended.

Flags: list qualify-runs
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--runId stringA specific run. Omit for this list's most recent one.

kairon list remove

Remove members from a list

Full description

Remove members from a list ({ asset, id, items }).

Flags: list remove
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--items requiredjson array jsonThe rows to remove, each named by any one identity the member could have been added with.

kairon list set

Set members' custom-column values

Full description

Write custom-column values on members ALREADY in a list ({ asset, id, items }, ≤500).

Flags: list set
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--items requiredjson array jsonThe rows to write, each naming its subject plus the custom-column `values` to set on it.

kairon list show

Show a list in the chat

Full description

Show the operator a list's members as a table inside the chat — the same table Kairon's list page shows.

Flags: list show
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--q stringCase-insensitive substring over the member's display fields.
--tags json array jsonKeep only members carrying EVERY tag named — an AND, not an OR. Matched case-insensitively; a name no tag has yields an empty page rather than an error.
--sort person|title|company|email|phone|industry|qualification|owner|added|sourceWhich column to order by. Leads: person, title, company, email, phone, qualification, owner, added, source. Companies: company, industry, qualification, owner, added. Naming a field the asset does not have is refused. Omit for the default, newest-added first.
--direction asc|descOrder direction; read as `asc` once a `sort` field is named.
--qualificationStatus json jsonKeep members whose ICP verdict is ANY OF these: qualified, disqualified, unevaluated. `unevaluated` means nobody has judged them — never that they failed.
--ownerId json jsonKeep members owned by ANY OF these user ids. Ownership rides the entity, not the list.
--tagId json jsonKeep members carrying ANY OF these tag ids — an OR, and the counterpart to `tags` above, which is an AND over NAMES.
--addedAfter stringKeep members added to THIS list at or after this ISO timestamp.
--addedBefore stringKeep members added to THIS list strictly before this ISO timestamp.
--hydrated booleantrue keeps members whose LinkedIn facts have been loaded; false keeps the ones nobody has fetched yet (they have no size or HQ to filter on).
--column json array jsonKeep members matching EVERY predicate over this list's custom columns. A name the list does not have is refused, so a typo cannot read as 'no matches'.
--signalKey json jsonLeads only. Keep members that arrived from ANY OF these signals.
--crmStage json array jsonLeads only. Keep members standing at ANY OF these pipeline stages.
--emailState has|missing|unaskedLeads only. Narrow by what is known about the person's work email: `has` (an address is on file), `missing` (a finder was already asked and came back empty — asking again costs money and learns nothing), or `unasked` (nobody has looked). `unasked` is the one an enrichment pass wants: it IS the remaining work, so a pass can stop, resume tomorrow, and never pay twice for the same person.
--phoneState has|missing|unaskedLeads only. The same three states for the person's phone: `has`, `missing` (a finder already came back empty), `unasked` (nobody has looked — the worklist for a `lead_phone_set` pass).
--employeeMin integerCompanies only. Keep companies with AT LEAST this many employees.
--employeeMax integerCompanies only. Keep companies with AT MOST this many employees.
--industry json array jsonCompanies only. Keep companies carrying ANY OF these industries, matched case-insensitively against the whole industry list, not just the one shown as `subtitle`.
--hqCountry json array jsonCompanies only. Keep companies whose HQ is in ANY OF these ISO-2 country codes.

kairon list update

Rename a list, or set its custom columns

Full description

Rename a list and/or replace its custom columns ({ asset, id, name, columns? }).

Flags: list update
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstring
--name requiredstringThe list's name. ALWAYS required here, even when you only mean to change `columns` — send the current name back to keep it.
--columns json array jsonThe WHOLE ordered custom-column set, replacing what is there. Omit to leave the columns alone; [] removes them all. Carry `renameFrom` to rename a column and keep every member's values under the new name.
--audience json jsonMake this list build itself from a rule over the org's OWN leads, instead of adding people by hand. `include` selects; `exclude` (optional) removes from that selection; inside one condition the fields AND together and the values in a field OR together; a group's `match` is `all` (AND) or `any` (OR) across its conditions. The rule only ever ADDS: whoever matches becomes an ordinary member and stays one, so a campaign's own first message — which moves the person off `on_hold` — cannot cancel their sequence. It re-runs nightly, so people who reach the stage later join by themselves. TWO THINGS TO GET RIGHT. `on_hold` fills the instant a campaign's last message goes out, so pair it with `exclude: { match: 'all', conditions: [{ lastContacted: '30d' }] }` unless you really mean to write to someone who heard from you yesterday — in the orgs we measured, 17-45% of the Nurture pile had been contacted inside 30 days. And there is no pause: clearing the rule with `audience: null` is the only way to stop it, and the members it already added stay. Use `audience_preview` first to see how many people the rule selects. Omit this field to leave the current rule untouched; send null to clear it (the members it already added stay).

kairon message

kairon message delete

Delete (retract) a sent message

Full description

Retract a message YOU sent, addressed by the chatId and message id that chat_messages returns.

Flags: message delete
FlagTypeWhat it is for
--chatId requiredstring
--messageId requiredstringThe message's `id` from chat_messages.

kairon message edit

Edit a sent message

Full description

Replace the body of a message YOU sent, addressed by the chatId and message id that chat_messages returns.

Flags: message edit
FlagTypeWhat it is for
--chatId requiredstring
--messageId requiredstringThe message's `id` from chat_messages.
--text requiredstringThe replacement body. It overwrites the message for the recipient too.

kairon message send

Send a direct message

Full description

Send a direct message.

Flags: message send
FlagTypeWhat it is for
--chatId stringReply in this existing conversation (from chat_list). Use this, or `target`.
--target json jsonOpen a NEW conversation with this person. Use this, or `chatId`.
--text requiredstringThe message body, as it will be sent. Em dashes and curly quotes become plain punctuation; nothing else rewrites it.
--attachments json array json
--cc json array jsonEMAIL conversations only: up to 5 addresses to copy on the reply, e.g. your main address so the conversation continues there. Refused on a LinkedIn conversation.
--clientToken stringYour own idempotency key. Send the SAME token when retrying after a lost response and the message is not sent twice.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "write-messages" }) and of framework_get({ slug: "outreach" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon message style-get

Read how the Author writes messages, in their own words

Full description

The Author's message style: free text about how they write invites, messages and InMails — their real messages as examples, how they open, how long and how formal they are.

Takes no flags.

kairon message style-set

Save how the Author writes messages

Full description

Replace the Author's message style, whole.

Flags: message style-set
FlagTypeWhat it is for
--text requiredstringThe COMPLETE message style — it REPLACES what is stored. Put the Author's real messages in as examples, then how they open, how long they write, how formal they are and what their language is like. Kairon's own writers never read it; it is for you, before you write a message for them. An empty string removes it. At most 8000 characters.

kairon newsletter

kairon newsletter subscribers

List a newsletter’s subscribers

Full description

The people who subscribed to YOUR OWN LinkedIn newsletter — the warmest audience LinkedIn holds, since each one read your writing and chose to keep receiving it.

Flags: newsletter subscribers
FlagTypeWhat it is for
--newsletter requiredstringThe newsletter, as its URL (https://www.linkedin.com/newsletters/<name>-<id>/) or its bare numeric id. It must be a newsletter the connected seat OWNS — LinkedIn serves this list to the author only.
--cursor stringContinue from a previous page. Omit for the first page.
--count integerSubscribers per page (default 50, max 100). LinkedIn refuses anything higher — asking for 250 fails the whole call, it does not clamp.
--intoList stringAppend this page’s subscribers to one of your lead lists, by name or id. Combine with `exhaust` to walk the whole audience into it without any of it crossing your context.
--exhaust booleanPage server-side until the results run out, instead of returning a cursor for you to send back. Requires `intoList`: every page is appended there and NO hits come back, only the totals — which is the point, since neither the hits nor the cursor then cross your context. Stops at `maxResults` and hands back a `cursor` to resume from. Each page still costs one metered action.
--maxResults integerHow many hits an `exhaust` run collects before it stops (default 500, max 2000). Ignored without `exhaust`. Raise it when you know the audience is large and you mean to spend the actions.
--readReceipts json jsonRequired with `intoList`: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon owner

kairon owner set

Assign an owner to leads or companies

Full description

Make one teammate responsible for the named leads or companies.

Flags: owner set
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of row these items are — people or companies.
--items requiredjson array jsonThe rows to assign, each naming its subject by ONE of `memberId`, `url`, or `providerId`.
--owner requiredjson jsonWho to assign every item to — one org member, by `userId` or `email`. The same owner is set on all of them.

kairon pipeline

kairon pipeline board

Read the pipeline board

Full description

Where every one of this org's people stands.

Flags: pipeline board
FlagTypeWhat it is for
--stage new|invite_sent|connected|contacted|replied|interested|meeting_booked|won|on_hold|lost|discardedReturn this column's people as well as the counts. Omit for counts only, which is what "how is the pipeline doing" needs.
--lastContacted stringNarrow to people last contacted inside a window: `7d`, `30d`, `90d`, `never`, or an explicit `YYYY-MM-DD..YYYY-MM-DD`. Narrows the counts as well as the people.
--cursor stringResume the named column from a previous call — pass the `cursor` it returned.
--limit integerHow many people to return when `stage` is named.

kairon pipeline stage-set

Move people on the pipeline board

Full description

Record where people now stand: new, invite_sent, connected, contacted, replied, interested, meeting_booked, won, on_hold, lost, or discarded.

Flags: pipeline stage-set
FlagTypeWhat it is for
--items requiredjson array jsonThe people to move, each naming its subject by ONE of `memberId`, `url`, or `providerId`.
--stage requirednew|invite_sent|connected|contacted|replied|interested|meeting_booked|won|on_hold|lost|discardedWhere they now stand. The ladder runs new → invite_sent → connected → contacted → replied → interested → meeting_booked → won | lost. `new` is where a lead nobody has acted on sits; `invite_sent` is an invitation not yet accepted; `connected` is accepted with nothing said yet; `contacted` means there is a message they can read. You may move someone backward as well as forward. Two stages sit outside the ladder, for people nobody is working: `on_hold` keeps them and does nothing for now, and `discarded` means never contact them again — which also adds them to the exclusion list, ending any campaign they are in.

kairon post

kairon post interactions

Who engaged with one post

Full description

Everyone who commented on or reacted to ONE named post, by its LinkedIn URL — the audience a post already earned, each person carrying HOW they engaged (their comment text, or which reaction), which is the warmest opening line outreach get…

Flags: post interactions
FlagTypeWhat it is for
--url requiredstringThe post — its LinkedIn permalink (…/posts/… or …/feed/update/…) or its bare `urn:li:activity|ugcPost|share:<id>`. A shortened `lnkd.in` link does NOT work: it carries no post id, so expand it first.
--intoList stringWhere this page's PEOPLE are appended — always a leads list. Only the person is added; the post and how they engaged are why they are here, not members. Pair with `exhaust` to sweep the whole post in one call.
--cursor string
--exhaust booleanPage server-side until the results run out, instead of returning a cursor for you to send back. Requires `intoList`: every page is appended there and NO hits come back, only the totals — which is the point, since neither the hits nor the cursor then cross your context. Stops at `maxResults` and hands back a `cursor` to resume from. Each page still costs one metered action.
--maxResults integerHow many hits an `exhaust` run collects before it stops (default 500, max 2000). Ignored without `exhaust`. Raise it when you know the audience is large and you mean to spend the actions.
--readReceipts json jsonRequired with `intoList`: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon post media-upload

Upload files for a LinkedIn post

Full description

Show the operator an upload box in the chat, to add photos, a video or a PDF from their own computer to a LinkedIn post.

Takes no flags.

kairon post publish

Publish a LinkedIn post

Full description

Publish a LinkedIn post NOW from the CALLER'S OWN account — public at once.

Flags: post publish
FlagTypeWhat it is for
--text requiredstringThe post as it will read on LinkedIn, at most 3000 characters.
--media json array jsonThe files to attach, in order. Each is `{ id }` from the upload box, `{ fileName, mimeType, url }` (https, fetched server-side), or `{ fileName, mimeType, dataBase64 }` (one per post, at most 3 MB). Omit for a text-only post.
--mentions json array jsonPeople or companies to tag. Write `{{0}}`, `{{1}}`… in `text` where each goes.

kairon profile

kairon profile comments

The comments a person has written

Full description

A page of the comments this person has WRITTEN, on anyone's posts, newest first — the mirror of post_interactions, which answers who engaged with ONE post.

Flags: profile comments
FlagTypeWhat it is for
--target requiredjson jsonWho this acts on — one LinkedIn person or company, named by URL, vanity slug, or provider id.
--cursor string

kairon profile posts

A profile's recent posts

Full description

A page of a profile's recent posts (transient — not persisted).

Flags: profile posts
FlagTypeWhat it is for
--target requiredjson jsonWho this acts on — one LinkedIn person or company, named by URL, vanity slug, or provider id.
--cursor string

kairon profile reactions

The posts a person has reacted to

Full description

A page of the posts this person has REACTED to, newest first — the same attention feed profile_comments reads, with no words in it.

Flags: profile reactions
FlagTypeWhat it is for
--target requiredjson jsonWho this acts on — one LinkedIn person or company, named by URL, vanity slug, or provider id.
--cursor string

kairon profile edit

Edit your own LinkedIn profile

Full description

Change how the CALLER'S OWN LinkedIn profile looks — headline (max 220 chars), about (the About section, max 2600), picture, and banner (the wide image behind the top of the profile).

Flags: profile edit
FlagTypeWhat it is for
--headline stringThe line under your name on LinkedIn. Omit to leave it as it is; there is no way to clear it from here.
--about stringThe whole About section, replaced outright — send the full text you want, not an addition to it. Omit to leave it as it is.
--picture json jsonA new profile picture. Pass the bytes as `dataBase64`, or an https `url` we fetch — one or the other, never both. Must be a jpeg, png, gif or webp.
--banner json jsonA new background banner, the wide image behind the top of the profile. Same two sources and same image types as `picture`.

kairon qualification

kairon qualification get

Read one member's qualification verdict

Full description

WHY one lead or company carries the verdict it does ({ asset, id }) — the stored scorecard.

Flags: qualification get
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of list: 'leads' (people) or 'companies'.
--id requiredstringThe member's id, exactly as `list_members` returned it — a lead id under `asset: 'leads'`, a company id under `asset: 'companies'`.

kairon qualification set

Decide about people or companies yourself

Full description

Say whether these people — or, with asset: 'companies', these companies — are worth reaching out to, in your own judgement, instead of waiting for Kairon to decide.

Flags: qualification set
FlagTypeWhat it is for
--asset leads|companiesWho you are deciding about: 'leads' (people, the default) or 'companies'. Companies are named by `memberId` (from `list_members`), `url` or `providerId`, like people.
--items requiredjson array jsonThe people (or companies) to decide about, each naming its subject by ONE of `memberId`, `url`, or `providerId`.
--qualification requiredjson jsonYour own verdict: `qualified` to say these people are worth reaching out to even if the ICP disagrees, `disqualified` to keep them out even if it agrees. Pass `null` to take your verdict back and let the ICP decide again. Your verdict wins for as long as it stands: it is what the lists show, what the filters match, and what the campaigns obey — while Kairon goes on judging underneath, so taking it back costs nothing and restores what the ICP had decided.

kairon recruiter

kairon recruiter saved-searches

List Recruiter saved searches

Full description

The searches this seat has SAVED in LinkedIn Recruiter, by name.

Flags: recruiter saved-searches
FlagTypeWhat it is for
--keywords stringNarrow the list by name. Omit to list everything the seat has saved.
--limit integerHow many to return (default 10, max 100).

kairon seat

kairon seat list

List the seats you can send from

Full description

The LinkedIn seats this organization can send FROM (the campaign wizard's sender picker), every one connected and ready.

Takes no flags.

kairon signal

kairon skill

kairon skill get

Read one skill

Full description

One playbook in full, as markdown, by a name from skill_list — call that first; an invented name is a 404.

Flags: skill get
FlagTypeWhat it is for
--name requiredstringWhich playbook to fetch — a `name` from `skill_list`.

kairon skill list

List the available skills

Full description

Kairon's playbooks — how to do each job well: onboarding, Sales Navigator, list building, campaigns, writing messages and posts, what to do next.

Takes no flags.

kairon source

kairon source delete

Detach a lead list's signal source

Full description

Detach the source from a lead list.

Flags: source delete
FlagTypeWhat it is for
--listId requiredstringThe lead list whose source this addresses, from list_list or list_create. At most one source exists per list, so this is the source's address — there is no separate source id.

kairon source get

Read a lead list's signal source

Full description

The source attached to a lead list — the recurring feed that makes it a SIGNAL-BASED list, growing itself over time.

Flags: source get
FlagTypeWhat it is for
--listId requiredstringThe lead list whose source this addresses, from list_list or list_create. At most one source exists per list, so this is the source's address — there is no separate source id.

kairon source requalify

Re-qualify a source run's candidates against the current ICP

Full description

Re-judge people a source run already decided on, against the source's CURRENT ICP — the fix after the ICP was loosened and the people it rejected now show as "seen before".

Flags: source requalify
FlagTypeWhat it is for
--leadIds requiredjson array jsonThe candidates to re-judge — each row's `leadId` from `source_runs` with this `runId`. An id that is not a candidate of this run counts as `failed`.
--listId requiredstringThe lead list whose source this addresses, from list_list or list_create. At most one source exists per list, so this is the source's address — there is no separate source id.
--runId requiredstringThe run whose candidates to re-judge, from `source_runs`.

kairon source run

Run a lead list's signal source now

Full description

Run the source now instead of waiting for its daily run, and return the run that started.

Flags: source run
FlagTypeWhat it is for
--listId requiredstringThe lead list whose source this addresses, from list_list or list_create. At most one source exists per list, so this is the source's address — there is no separate source id.

kairon source runs

Read a signal source's runs, or one run's candidates

Full description

What the source actually did.

Flags: source runs
FlagTypeWhat it is for
--listId requiredstringThe lead list whose source this addresses, from list_list or list_create. At most one source exists per list, so this is the source's address — there is no separate source id.
--runId stringA run id from this tool's own summary page. Given, the result is THAT run's candidates — one row per person the run considered, with the outcome that decided them. Omitted, the result is the run history: when each ran, and how many it appended.
--limit integerRows per page, 1-100. Defaults to 25.
--cursor stringThe `cursor` from the previous page. A cursor minted for the run history cannot be used against a run's candidates, or the other way round — a mismatched token restarts from the first page rather than paging the wrong thing.

kairon source set

Attach or replace a lead list's signal source

Full description

Make a lead list SIGNAL-BASED, or change the one it already is: the signals that should feed it, and optionally an ICP every new person must pass (omit it and everyone the signals find is added; lookalike, changed_jobs, posted_recently and…

Flags: source set
FlagTypeWhat it is for
--listId requiredstringThe lead list whose source this addresses, from list_list or list_create. At most one source exists per list, so this is the source's address — there is no separate source id.
--icpId json jsonThe ICP every new person must pass before joining the list, from icp_list. Its ACTIVE version is the check, so revising the ICP changes future runs. Omit it or pass null for no ICP: then everyone the signals find is added. This is a full replacement, so on a list that HAS an ICP, omitting it removes the check — send back the `icp.id` source_get gave you to keep it. Six signals also SEARCH with the ICP and need one: lookalike, changed_jobs, posted_recently, company_raised_funds, company_leadership_change, company_hiring. Changing the ICP restarts those six from the top of their feed; the others keep their place.
--signals requiredjson array jsonThe COMPLETE set of signals this source should carry — at least one. Any signal not listed here is removed. Echo each kept signal with the `id` source_get gave it, or it is treated as new and restarts from the top of its feed.
--status active|pausedWhether the source keeps feeding the list. `paused` stops it without losing anything — the signals, their places in their feeds, and every member already found all survive, and resuming carries on where it left off. Use this rather than source_delete to stop a list growing for a while. Omitted leaves the current setting; a new source starts `active`.
--contactFilter.buckets json array jsonWhich contact-history buckets may enroll: `new` (no conversation either way, and nothing a Kairon campaign sent), `unanswered` (we messaged, no reply), `in_conversation` (they wrote to us). Unique, at least one. All three means enroll everyone. Anyone outside the selected buckets is skipped, not queued, so a narrow set is why a large audience enrolls almost nobody.
--contactFilter.scope seat|orgWhose prior-contact history is read: `seat` (this campaign's sending seat) or `org` (every LinkedIn seat). Copying a `seat` filter onto a DIFFERENT seat changes what it means — the new seat's history is empty, so people the original filter excluded now enroll.
--dailyTarget integerHow many qualified people this list should gain per day (UTC), 1-1000. A floor, not a cap: every event signal still runs in full first, and the lookalike signal then keeps searching until the day's total reaches this number, the search runs out, 30 people in a row fail the ICP (when the ICP describes companies: 10 companies in a row where nobody fits), or 20 companies (or result pages) in a row add nobody (it picks up from there the next day). Only the lookalike fills the gap, so on a source without one this only reports progress. Omitted leaves the current setting; a new source starts at 30.
--peoplePerCompany integerHow many people a walk that goes company by company takes at each company, 1-100. Applies to the lookalike (when the ICP describes companies) and to the recently-raised-funds and new-senior-leadership signals. Higher means fewer companies and less variety, but more of a big employer. Omitted leaves the current setting; a new source starts at 3.
--seatId stringWhich workspace seat (a channel account id from seat_list) reads this list's SEAT signals: viewed_my_profile, recently_connected and company_followers, and any signal whose own search is measured from a seat (firstDegreeOnly, postedByMe, postedByFollowed or inYourNetwork in its config, or a networkDistance-style filter in the ICP). Every other signal reads on Kairon's own accounts and needs no seat. Any member may pick any connected seat. Omitted: the list keeps its seat, else takes yours if it can run them; if neither works the call is refused with SOURCE_SEAT_REQUIRED, which lists the seats that can. Refused with SOURCE_SEAT_CANNOT_RUN when the seat lacks what a signal needs (a paid licence for viewed_my_profile, page admin for company_followers, Sales Navigator for a viewer-relative ICP). Ignored when no signal needs a seat.
--acceptExtraListCharge booleanThe workspace's plan includes a number of growing lists (lists whose source is active). Turning a list on past that number costs the plan's price for an extra list, every month, billed to the organization; on a plan that sells none it is refused. A call that turns a list on past the included number is REFUSED unless this is true, and the refusal carries the price: ask the user first, then retry with it. Ignored when the call turns no list on, or the list fits. A list carries at most 3 signals.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "list-building" }) and of framework_get({ slug: "targeting" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon tag

kairon tag delete

Delete a tag

Full description

Removes the tag from the organization AND from every lead and company wearing it, in one act.

Flags: tag delete
FlagTypeWhat it is for
--id requiredstring

kairon tag save

Create or update a tag

Full description

Without id, creates a tag.

Flags: tag save
FlagTypeWhat it is for
--id string
--name stringThe tag name. Required when creating; on an existing `id` it renames the tag everywhere.
--color stone|clay|moss|sky|plum|amber|rust|slateDisplay colour for the tag. Omit and one is chosen.

kairon tag set

Set which tags a lead or company carries

Full description

Replaces each named subject's WHOLE tag set — so send every tag it should end up with, not just the new one, and send [] to clear it.

Flags: tag set
FlagTypeWhat it is for
--asset requiredleads|companiesWhich kind of row these items are — people or companies.
--items requiredjson array jsonThe rows to tag, each naming its subject by ONE of `memberId`, `url`, or `providerId`.

kairon webdata

kairon webdata find

Find a data endpoint outside LinkedIn

Full description

Search, in plain words, for a third-party data endpoint Kairon can run for you — data OUTSIDE LinkedIn: tweets by handle, a Google Maps listing, a company's reviews, a person's record at a data broker, and hundreds more.

Flags: webdata find
FlagTypeWhat it is for
--query requiredstringWhat data you are after, in plain words. Up to 1000 characters.
--limit integerHow many matches to return. Default 5, at most 40.

kairon webdata inspect

Read one data endpoint's inputs and price

Full description

The full card for one endpoint webdata_find returned, by its provider and endpoint: what it does, the exact input schema webdata_run expects (path, query and body parameters), the provider's price, a link to the provider's own docs, and an…

Flags: webdata inspect
FlagTypeWhat it is for
--provider requiredstringThe `provider` slug from `webdata_find`, e.g. `apify`.
--endpoint requiredstringThe `endpoint` path from `webdata_find`, e.g. `/apidojo/tweet-scraper`.

kairon webdata quote

Price a data run before running it

Full description

What THIS organization will pay for one run of an endpoint with exactly this input — the provider's price plus Kairon's margin — and the quoteId that webdata_run requires.

Flags: webdata quote
FlagTypeWhat it is for
--provider requiredstringThe `provider` slug from `webdata_find`, e.g. `apify`.
--endpoint requiredstringThe `endpoint` path from `webdata_find`, e.g. `/apidojo/tweet-scraper`.
--input json jsonThe endpoint's parameters, as `{ body?, queryParams?, pathParams? }` — each section filled per the matching section of its `webdata_inspect` schema. Omit for an endpoint that takes none. Must be IDENTICAL between `webdata_quote` and `webdata_run`.
--expectedResults integerFor a per-result endpoint: how many results you expect back — the cap you put in `input`, or your honest estimate. Turns a per-result price into an `estimatedUsd`.

kairon webdata result

Read back a data run that was still going

Full description

Fetch the outcome of a webdata_run that came back with status other than COMPLETED, FAILED, BLOCKED, STOPPED or TIMED_OUT — a run the provider was still working on when the 60-second wait ended.

Flags: webdata result
FlagTypeWhat it is for
--runId requiredstringThe `runId` a still-running `webdata_run` returned.

kairon webdata run

Run a data endpoint (spends the organization's allowance)

Full description

Run one endpoint and get its data back.

Flags: webdata run
FlagTypeWhat it is for
--provider requiredstringThe `provider` slug from `webdata_find`, e.g. `apify`.
--endpoint requiredstringThe `endpoint` path from `webdata_find`, e.g. `/apidojo/tweet-scraper`.
--input json jsonThe endpoint's parameters, as `{ body?, queryParams?, pathParams? }` — each section filled per the matching section of its `webdata_inspect` schema. Omit for an endpoint that takes none. Must be IDENTICAL between `webdata_quote` and `webdata_run`.
--quoteId requiredstringThe `quoteId` `webdata_quote` returned for this exact provider, endpoint and input.

kairon webhook

kairon webhook deliveries

Read what an endpoint was sent, and what it answered

Full description

The recent deliveries to one endpoint, newest first: which event, when, whether it landed, how many attempts it took, and the status code the endpoint answered with.

Flags: webhook deliveries
FlagTypeWhat it is for
--endpointId requiredstringThe endpoint whose recent deliveries to read.

kairon webhook list

Read the organization's webhook endpoints

Full description

Every URL this organization has asked Kairon to POST events to, with the event types it wants, whether it is on, and how its last delivery went.

Takes no flags.

kairon webhook set

Register or change a webhook endpoint

Full description

Without id, registers a new endpoint and returns its signing secret — the only time that secret is ever shown, so hand it to the operator immediately and tell them we cannot show it again.

Flags: webhook set
FlagTypeWhat it is for
--id stringOmit to register a new endpoint. Present to change that one.
--url stringWhere to POST. Must be https and must resolve to a public address. Required when creating.
--description stringThe operator's own label for it, e.g. 'Our HubSpot sync'.
--enabledEvents json array jsonWhich event types to send. Defaults to all of them when creating.
--status enabled|disabled_by_userTurn it off without deleting it, or back on. Re-enabling clears its failure streak.

kairon webhook test

Send a test event to a webhook endpoint

Full description

Sends one sample lead.stage.changed (an invented person) to the endpoint right now, signed like a real event, and returns what the endpoint answered: attempt.statusCode (null when nothing answered) and attempt.error.

Flags: webhook test
FlagTypeWhat it is for
--id requiredstringThe endpoint to send the sample event to.

kairon workspace

kairon workspace rename

Rename the workspace

Full description

Change the organization's own display name, exactly as it appears across the Kairon app.

Flags: workspace rename
FlagTypeWhat it is for
--name requiredstringThe workspace's new display name.

kairon writing

kairon writing check-judge

Judge a draft against the rules, without sending it

Full description

Run one draft past the SAME judge a real send goes through, and get a pass/fail plus a reason for every rule that governs it.

Flags: writing check-judge
FlagTypeWhat it is for
--draft requiredstringThe exact text to judge, as it would go out.
--surface requiredpost|commentWhat kind of writing this is. It decides which rules apply: `general` plus this section and nothing else. Messages are not checked, so there is no `dm`.
--context stringWhat the writer was working from: the post a comment answers, the thread a reply continues, who the message is to. Rules like "does not echo their words back" or "reacts to something specific in the post" CANNOT be judged without it — omit it and they are judged on the draft alone, which reads as a pass.
--template stringThe operator's own template seed, when this draft was written from one. Its fixed text is then exempt from the style rules (the writer may only fill the slots, so failing it for the operator's own words asks it to fix what it may not touch), and template fidelity is measured against it.

kairon writing check-list

Read the rules every draft is held to

Full description

The rules Kairon holds posts and comments to, in three sections: general (both), post, comment.

Flags: writing check-list
FlagTypeWhat it is for
--sections json array jsonRead only these sections. Omit for all three. `general` applies to posts and comments; the other two govern that surface alone. Messages have no section: they are not checked.

kairon writing check-set

Save the Author's own rules for one section

Full description

Replace the Author's OWN rules for ONE section, whole.

Flags: writing check-set
FlagTypeWhat it is for
--section requiredgeneral|post|commentWhich section to replace. A writer is judged against `general` plus its own section and nothing else, so a rule about comments belongs in `comment`, never in `general`.
--checks requiredjson array jsonThe COMPLETE desired list for that section — it REPLACES what is stored. Include every rule to keep, each with its `id` from `writing_check_list` so its history survives, plus any new ones without an id. Omit a rule to delete it. An empty array clears the section. At most 20; Kairon's own rules do not count against it.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "writing-checks" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon writing check-shared-set

Switch one of Kairon's own rules on or off

Full description

Switch one of Kairon's SHARED rules on or off for this Author, by a key from writing_check_list.

Flags: writing check-shared-set
FlagTypeWhat it is for
--key requiredstringA shared rule's `key` from `writing_check_list` (e.g. `comment.no_first_name_opener`). A key that is not a real shared rule is refused rather than stored.
--enabled requiredboolean`false` switches Kairon's rule off for this Author; `true` switches it back on.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "writing-checks" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

kairon writing style-get

Read how the Author comments, in their own words

Full description

The Author's comment style: free text Kairon follows every time it writes a comment for them — their real comments as examples, how they use emoji, their kind of English.

Takes no flags.

kairon writing style-set

Save how the Author comments

Full description

Replace the Author's comment style, whole.

Flags: writing style-set
FlagTypeWhat it is for
--text requiredstringThe COMPLETE comment style — it REPLACES what is stored. Put the Author's real comments in as examples, then how they use emoji, how they bring themselves in and what their English is like. Guidance, never judged: anything that must hold every time belongs in a `comment` rule instead. An empty string removes it. At most 8000 characters.
--readReceipts json jsonRequired: the `readReceipt` of skill_get({ name: "comment-voice" }). Read them BEFORE you start — they hold what Kairon measured to work for this job. A missing or expired receipt is refused and the refusal names what to read.

Flags

Flags are derived from each tool input schema, not written by hand, which is why they match the tool exactly. Three shapes get three treatments.

Scalars are plain flags

A string, number or boolean becomes --flag and takes its value literally. An enum shows its choices in the type column.

Nested objects are dot paths

A tool input nests freely, so a nested field becomes --config.keyword rather than a flattened name that could collide with another tool field.

Arrays and unions take JSON

There is no honest flat spelling for "an array of either a member id or a URL", so those flags take JSON text. They are marked json in the table below.

Typos are caught before the network

Input is checked against the cached schema before any call, so a misspelled flag costs nothing and names itself: it tells you the option is unknown and suggests the one you meant.

Every command also accepts

--server <url>
Target a specific Kairon (default: KAIRON_API_URL, else production)
--json <json>
Pass the entire tool input as one JSON object
--refresh
Re-fetch the tool catalogue before running
-h, --help
Show help
-v, --version
Show the CLI version
And the escape hatch, when flags get in the way
kairon list create --json '{"asset":"leads","name":"Q3"}'

Output and exit codes

The result is JSON on stdout. Everything a human reads goes to stderr, so a pipe stays clean with no flags. A command that succeeds exits 0. A command that fails exits non-zero, writes nothing at all to stdout, and leads with a stable error code you can branch on rather than prose you would have to pattern-match.

Piping works with no flags
kairon campaign stats --id camp_… | jq '.funnel'
A failure names its code
$ kairon list get --asset leads --id list_01… ; echo "exit=$?"
kairon list get failed: COMMON_NOT_FOUND
{
  "code": "COMMON_NOT_FOUND",
  "params": { "resource": "lead_list" }
}
exit=1

Environment and headless use

For CI, a cron job or a container, there is no browser to open. Pass a token instead and the CLI needs no stored credentials at all.

KAIRON_TOKEN
Use this access token and ignore stored credentials entirely.
KAIRON_API_URL
Default server. The --server flag beats it, and production is the fallback.
KAIRON_CONFIG_DIR
Where credentials live. Defaults to ~/.kairon.
No ~/.kairon needed
KAIRON_TOKEN=<access token> kairon whoami

Acting as someone else

Kairon staff can act as any user; an owner or admin can act as a member of their own organization who does not outrank them. One command in, one command out, nothing to type in between.

kairon impersonate list --search acme
kairon impersonate start --user ana@acme.com
kairon chat list
kairon impersonate stop

The mode belongs to this login, not to you

Signing in registers a fresh client each time, so your terminal, your assistant and your cron each have their own. Acting as someone here does not redirect the 3am job.

It ends 60 minutes after your last call

Not 60 minutes after it started. Working never interrupts you; leaving for lunch ends it.

Every command under it says so on stderr

One line naming who you are acting as. stdout is untouched, so a pipe keeps working.

Only someone with a LinkedIn seat

Acting as a seatless user would reach nothing, so impersonate list tags each candidate with whether they have one.

Troubleshooting

Every command says there is no seat

The account has no LinkedIn account connected, or the plan is not active. Connect one in Kairon and run kairon whoami again. Commands act as that seat, so nothing works without it.

A command does not exist

Commands come from the server, cached per server URL under ~/.kairon/tools/, and the cache has no expiry because a tool set changes on deploy and not on a schedule. Run the command again with --refresh to re-fetch it.

It asks you to sign in again

Access tokens last 30 days and refresh silently. When the refresh token finally expires after 90 days you get one sentence and the command to run.

Signing out does not revoke anything

kairon logout deletes the local credentials. The server issues opaque tokens with no revocation endpoint, so the access token stays valid there until it expires. The command says so rather than implying a revocation that did not happen.