email-campaigns —
create → audience → messages → coverage → launch — with LinkedIn-specific
deltas: steps run from order 0 (the connection request), messages are
body-only, and there’s an extra sendability report. For a guided walkthrough
see How to launch a campaign.
linkedin-campaigns is a platform-mode command. Before running it:landbase-cli auth login— authenticate the session.landbase-cli account set— pick and persist the target account.landbase-cli contacts-import start— import contacts; this produces the tag the campaign targets.- A connected LinkedIn account, configured in the web app — required to launch. Launch sends from every connected LinkedIn account on the account.
linkedin-campaigns requires an account id...; pass --account=<id> per call as an escape hatch.linkedin-campaigns create
Create a campaign draft. Reads a JSON body describing the audience and the message sequence, and returns{ campaignId, status }. A template campaign
carries one shared message per message-bearing step; a personalized campaign
carries a skeleton sequence whose per-contact copy you upload later with
messages.
Usage
string
required
Path to a JSON file with the campaign definition, or
- to read it from
stdin. See create --json config below for the body shape.{ campaignId, status }; counts come from
status after launch.
create --json config
audience names its tag by exactly one of tagName (preferred — the
human-readable name contacts-import shows you) or tagId (the numeric id). If
a name matches more than one tag the call fails with tag_name_ambiguous;
re-issue with the explicit tagId.
Each sequence.steps[] entry:
Example (template mode)
linkedin-campaigns audience
Export the campaign’s resolved contacts as one wide CSV so you (or an AI agent) can write one personalized message per contact, per message-bearing step. The file has the contact-context columns plus an emptymessage_<order> cell for
each message-bearing order. Fill those cells in place and resubmit the same
file with messages. Used only for personalized campaigns.
Usage
integer
required
The campaign (draft) id returned by
create.string
Write the CSV to this file and print a JSON summary to stdout. Without it, the
raw CSV is written to stdout.
integer
Cap the number of exported contacts (positive integer).
linkedin_url, first_name, last_name, title, company_name, company_website, industry, then message_<order> per message-bearing order.
linkedin_url is the join key and must stay exactly as exported; each
message_<order> is ≤ 5000 chars. message_0 is the connection-request note
(sent with the invite); message_1.. are follow-ups.
With --out, the CSV is written to the file and stdout is a JSON summary;
without --out, the raw CSV is written to stdout (not JSON):
orders are the message-bearing step orders that drive the message_<order>
columns.
linkedin-campaigns messages
Upload the filled wide CSV to the campaign. The back-end validates the file, matches rows bylinkedin_url, and ingests them asynchronously. Without
--watch the command returns the ingest-start response immediately; with
--watch it polls to a terminal phase and prints the final ingest status.
Usage
integer
required
The campaign id to upload messages for.
string
required
Path to the filled messages CSV (the same file exported by
audience).
Re-uploading a fixed file is a full replace. Terminal ingest phases:
completed, partial, failed.
The start response (without --watch):
--watch, the final status once terminal — the coverage.samples carry
LinkedIn URLs and ordered bodies:
coverage is null while the ingest is still in flight.
linkedin-campaigns coverage
Inspect message coverage before launching — which matched contacts have a complete message set. Bare, it returns the coverage report; with--show <linkedinUrl> it returns that one contact’s stored per-step messages.
Usage
integer
required
The campaign id to report coverage for.
string
A contact’s LinkedIn URL. Returns that contact’s stored messages instead of the
report.
coverage and sendability are draft-only reports. After launch they
return 409 coverage_unavailable / sendability_unavailable.matched is the resolved audience size, covered the
contacts with a complete message set, uncovered a sample still missing them:
--show <linkedinUrl> — one contact’s ordered messages (null if none yet):
linkedin-campaigns sendability
Explain why the sendable audience is smaller than the tag: totals plus a per-reason breakdown.sendable is what the campaign will message; excluded
is the count of tagged contacts not currently sendable. The contacts* reason
counts are independent diagnostics that may overlap and need not sum to
excluded.
Usage
integer
required
The campaign (draft) id.
coverage). sendable is what the campaign will
message (== total); excluded = tagged − sendable. The contacts* reason
counts are optional diagnostics that may overlap and need not sum to excluded:
linkedin-campaigns launch
Launch a draft. Takes no body — the campaign enrolls its audience and hands off to the send pipeline, sending from every connected LinkedIn account. Launch is blocked (campaign_coverage_incomplete) until every matched contact has a
complete message set. With --watch the command polls the status (up to 10
times, 10s apart) until it reaches a terminal state (target: scheduled).
Usage
integer
required
The draft campaign id to launch.
Returns
{ campaignId, status }:
--watch, stdout is the final
status object instead.
linkedin-campaigns status
Status for one campaign — type, lifecycle, and allocated/sent stats. Usageinteger
required
The campaign id.
{ campaignId, name?, status, campaignType?, stats? }. See
output schemas.
linkedin-campaigns list
List the account’s campaigns, newest first. Usage{ data: [...], totalCount }. See
output schemas.

