Skip to content
SSalesShiftDocs

Reference

vxcli salesshift

The SalesShift command group: the CRM, the prospect pool, sending, automation, money and the operational surfaces — 229 commands across 28 groups, aliased ss and sales. Five groups are documented in depth below with pasted terminal output; the full reference covers every one of them and is generated from the binary’s own --help, so it cannot drift from what the CLI accepts.

Install

The published installers detect OS and CPU, verify a sha256, and drop the binary in a per-user bin directory — no sudo, no admin.

Linux / macOS
curl -fsSL https://vxcloud.io/download/cli/install.sh | sh
Windows (PowerShell)
irm https://vxcloud.io/download/cli/install.ps1 | iex

Both URLs, and the stable.txt version pointer beside them, answered 200 when this page was written. The installer honours VXCLI_VERSION, VXCLI_INSTALL_DIR (default $HOME/.local/bin) and VXCLI_BASE_URL.

Build from source

The SalesShift group moves quickly, so a source build is often ahead of the published installer.

Shell
cd vxnode/services/cli
go build -buildvcs=false -o vxcli .     # Go 1.21+; -buildvcs=false is required
./vxcli salesshift --help

Building is not installing

vxcli on your PATH is usually a symlink to vxnode/bin/vxcli, which is a copy of the build output — not the output itself. Building in services/cli leaves that copy untouched, so your shell keeps running the previous binary and every fix looks like it failed. Finish with cp -f vxcli ../../bin/vxcli.
Real output
SalesShift — sales email service (send, track, stats)

Usage:
  vxcli salesshift [command]

Aliases:
  salesshift, ss, sales

Available Commands:
  analytics      The numbers behind the dashboards
  billing        Your SalesShift plan — pricing, seats, invoices
  calendar       Meetings — agenda, events and invitations
  campaigns      Email campaigns and their reports
  companies      Accounts — the companies behind your contacts
  contacts       Your CRM contacts — the only records that are mailable
  contracts      Contracts — draft, send for signature, track and audit
  conversations  Reply threads — what came back from your sends
  deals          Pipelines and deals — the revenue board
  deliverability Inbox health, domain auth and placement — why mail lands or does not
  email          SalesShift email operations
  goals          Quota targets and the leaderboard
  invoices       Invoices — issue, send, chase and record payment
  leads          Prospect pool — search, reveal, save, convert (leads are NOT mailable until converted)
  lists          Contact lists — the audiences campaigns and sequences send to
  opportunities  The shared signal pool — buying and hiring signals
  quotes         Priced proposals — draft, get them approved internally, send
  reports        Saved and ad-hoc reports over the CRM datasets
  seo            Site audits, keyword tracking and rank checks
  sequences      Multi-step outbound sequences with delays, A/B variants and stop rules
  settings       Workspace settings — suppressions, team, integrations, mailboxes
  social         Social distribution — one post, every network, in parallel
  stats          SalesShift dashboard stats (contacts, deals, email funnel)
  subscriptions  Your customers' recurring revenue (NOT your own SalesShift plan)
  tasks          Tasks — description, due date, owner and target goal
  webmaster      Inspect a live URL, robots.txt and sitemap.xml
  worker         Tenant email-worker operations
  workflows      Automation workflows — the /automations canvas, from a terminal

Flags:
  -h, --help   help for salesshift

Global Flags:
      --config string   Config file (default is $HOME/.vxcloud/credentials.json)
      --debug           Enable debug mode
      --no-color        Disable color output
      --output string   Output format (text, json, yaml) (default "text")
      --quiet           Suppress non-essential output
      --verbose         Enable verbose output
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

The build used on this page reported version 2026.6.13-1516, windows/amd64, go1.25.5.

Authenticate

Every SalesShift command except worker health needs a credential. vxcli auth login writes one to $HOME/.vxcloud/credentials.json; the SalesShift commands read it back on each call and never prompt.

Shell
# Browser PKCE — the default when no other flag is given
vxcli auth login

# Developer API key
vxcli auth login -u alice -k xc_live_…

# Email + password
vxcli auth login --email [email protected] --password '…'

# Headless (SSH, CI): print a code, approve it elsewhere
vxcli auth login --device

How a credential is chosen

One rule, applied per request in ssAuthHeaders: a JWT beats an API key, and nothing else is consulted.

OrderConditionHeader sent
1access_token is non-empty in the configAuthorization: Bearer <jwt>
2otherwise api_key is non-emptyX-API-Key: xc_…
3neither is set, or the file cannot be readnothing is sent; the command exits 1 before any request goes out

The CLI does not refresh a JWT for you

There is no refresh in this path. When the stored access token expires — roughly an hour after login — the server answers 401 and the command prints not authorized — run `vxcli auth login`. Log in again.

Until 2026-08-12 that second login could refuse: the guard tested a is_valid flag written once at login and never revisited, so an expired session answered Already authenticated — use --forcewhile every command kept returning 401. It now decodes the token’s exp and logs in when it has actually expired, so --force is no longer needed to recover from a lapsed session.

Give a script a credential that outlives an hour

A password login stores an access token but no API key, so nothing can mint a fresh JWT once that hour is up — the SDKs are stuck too. Issue a developer key and put it in ~/.vxcloud/credentials.json as api_key; both the CLI and the SDKs then exchange it for a new token on their own and the expiry stops mattering.

Which host each command talks to

SalesShift is split across two services. The control plane owns the data and the masking decision; the tenant node owns the email worker. Both are resolved independently.

BaseResolution orderUsed by
VxCloudVXCLOUD_URLbase_url from the config (only if it looks public) → https://api.vxcloud.ioEvery command except worker health
NodeVX_NODE_URLNODE_URLnode_url from the config, written by vxcli auth loginfrom your tenant's default node record — e.g. https://node1.vxcloud.io. There is no host fallback: with no node resolved the command tells you to run vxcli node refresh rather than guessing.worker health only

worker health sends no credential at all

It is a plain http.Get against the node — the one SalesShift call with no auth header. Verified: with $HOME pointed at a directory containing no credentials.json, it still returned status healthy while leads quota in the same shell refused to run.

Global flags and output formats

FlagDefaultEffect
--outputtexttext, json or yaml. Honoured by every leads command. The email, stats and worker commands ignore it and always print text — verified by running --output json salesshift stats and getting the rendered table.
--config$HOME/.vxcloud/credentials.jsonAlternate credentials file.
--no-colorfalseDrops ANSI colour. Every capture on this page was taken with it.
--debug / --verbose / --quietfalseRoot-level flags; SalesShift adds no behaviour to them.

Under --output json or --output yaml the human chatter — the cost warning before a spend, the confirmation prompt — moves to stderr, so stdout stays a clean parseable stream. The price of a spend is still shown either way.

Shell
vxcli --no-color --output json salesshift leads quota
Real output
{
  "allowance": 2500000,
  "display": "27 / 2500000",
  "remaining": 2499973,
  "unlimited": false,
  "used": 27
}
Real output, captured 2026-08-13 against http://localhost:8741. Re-captured after the entitlement layer shipped. allowanceis now set by the plan, not by a constant in the router: 2,500,000 here is 100,000 reveals per seat × 25 seats on a granted Organization workspace, and the free tier’s figure is 5,000. used moves as the system is used.

Repeatable filters are not comma-separated

The filter flags use pflag’s StringArrayVar, not StringSliceVar. A value containing a comma stays one value, so --title "Director, Sales Operations"is a single substring rather than two OR’d ones. Repeat the flag to pass several.

Stats

vxcli salesshift stats

Called live

The SalesShift dashboard aggregate: CRM counts and the email funnel.

Calls
GET {vxcloud}/api/v1/salesshift/stats

No flags.

Shell
vxcli --no-color salesshift stats
Real output
  ▎ SalesShift stats  ────────────────────────────────────────────
    Contacts           37
    Companies          1
    Open deals         22
    Active sequences   1
    Emails sent        205
    Emails opened      21
    Emails replied     4
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

The endpoint returns more than this — open pipeline value, open tasks, a reply-category breakdown — but the command renders only the eight fields above. Read the rest with a direct API call.

Email

vxcli salesshift email send

Called live

Send one tracked email through the org's provider. The suppression gate and the daily caps are applied server-side and are not optional.

Calls
POST {vxcloud}/api/v1/salesshift/email/send
FlagTypeDefaultWhat it does
--torequiredstring""Recipient address.
--subjectrequiredstring""Subject. Merge tags such as {{first_name}} resolve against the contact record.
--bodystring""HTML body. Required unless --body-file is given.
--body-filestring""Read the HTML body from a file. A read error exits 1 before anything is sent.
Shell
vxcli --no-color salesshift email send \
  --to [email protected] \
  --subject "Docs example — vxcli salesshift email send" \
  --body "<p>Sent from the terminal while writing the CLI reference.</p>"
Real output
  ▎ Email sent  ──────────────────────────────────────────────────
    To                 [email protected]
    Provider           smtp
    Tracking ID        ea81efd0d7dc4a8388868e1e387c56d2
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

This sends a real message

There is no dry-run flag. The command exits 1 unless the response is HTTP 200 and successis true; on failure it prints the server’s detail, or its error when there is no detail.

vxcli salesshift email list

Called live

The org's outbound feed with its engagement state.

Calls
GET {vxcloud}/api/v1/salesshift/emails[?status=]
FlagTypeDefaultWhat it does
--statusstring""Filter by status — sent, opened, clicked, replied, bounced, unsubscribed, failed. Empty returns everything.
Shell
vxcli --no-color salesshift email list --status sent
Real output (first 10 of 50 rows)
  ▎ Emails (50)  ─────────────────────────────────────────────────
  [email protected] sent         opens=0   OAuth send proof OAuth
  [email protected]   sent         opens=0   OAuth send proof Lena
  [email protected]          sent         opens=0   Rotation proof for Priya
  [email protected]     sent         opens=0   Rotation proof for Ava
  [email protected]              sent         opens=0   Rotation proof for Sam
  [email protected]    sent         opens=0   Rotation proof for Omar
  [email protected]      sent         opens=0   Rotation proof for Tomas
  [email protected] sent         opens=0   Rotation proof for Marco
  [email protected] sent         opens=0   Rotation proof for Priya
  [email protected]       sent         opens=0   Rotation proof for Dana
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ. Addresses are printed in a fixed 28-character column (%-28v), so the first row’s longer address pushes the rest of its line right rather than widening the table.

The count in the heading is the number of rows the server returned for this page, not the size of the whole feed. There is no paging flag on this command.

Worker

vxcli salesshift worker health

Called live

Health of the Go email worker on your tenant node — the process that actually delivers a send.

Calls
GET {node}/api/v2/salesshift/email/health

No flags.

Shell
vxcli --no-color salesshift worker health
Real output
  ▎ Email worker  ────────────────────────────────────────────────
    Node               http://127.0.0.1:8744
    Status             healthy
    Providers          [smtp]
    Redis              true
    Domain rate/min    20
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Node echoes the base URL that was resolved, which is the quickest way to tell whether VX_NODE_URLtook effect. The loopback address above is simply what that particular run resolved to — a node running on the same machine. Your tenant's node is its own host, and the command will print that instead.

This is the only command in the group that reaches the tenant node, and the only one that sends no credential.

Leads — the prospect pool

The pool is global and lives on the control plane, not your node. Three rules run through every command here, and each is enforced in the output rather than left to the reader:

  • A lead is not mailable. Nothing in this group can email anybody. leads convert and its two bulk forms are the only route to a Contact, and they are where consent metadata is written.
  • A mask is not an address. An unrevealed row renders as s•••@kestreldata.example (masked — not revealed) and is labelled every time. has_email says an address exists; email_revealed says you may see it.
  • Reveal spends metered quota. Every spending path prints the cost before acting and needs --yes, or an interactive y/N. A pipe or a CI job that cannot answer counts as no.

vxcli salesshift leads facets

Called live

Counts per seniority, department, country, email status and industry for a filter set — the numbers you put beside filter checkboxes.

Calls
POST {vxcloud}/api/v1/salesshift/leads/facets
FlagTypeDefaultWhat it does
--qstring""Free text over name, title and company.
--titlerepeatablestringTitle contains. Repeat to OR several.
--exclude-titlerepeatablestringTitle must NOT contain. Repeat to exclude several.
--seniorityrepeatablestringOne of founder c_suite vp director manager senior entry.
--departmentrepeatablestringOne of engineering sales marketing finance hr ops legal executive.
--countryrepeatablestringISO-2 country code, e.g. AU. Upper-cased server-side.
--industryrepeatablestringIndustry, e.g. "Computer Software".
--email-statusrepeatablestringverified unverified guessed catch_all invalid.
--employeesrepeatablestringCompany size band, e.g. 51-200, 5000+.
--domainrepeatablestringCompany domain, e.g. northwind.example.
--keywordrepeatablestringCompany keyword, substring match — "saas" also matches "saas management".
--min-scoreint0Minimum quality score. 0 means no constraint.
--has-emailboolunsetOnly rows where an address exists. That is not permission to read one — it is still masked until revealed. Tri-state: leave it off for no constraint, --has-email=false to require rows with no address.
--has-phoneboolunsetOnly rows where a phone number exists. Tri-state, same as above.
Shell
vxcli --no-color salesshift leads facets --country AU
Real output
  ▎ Pool facets  ─────────────────────────────────────────────────
    Backend            go-node

  SENIORITY
    director                     33
    manager                      11
    founder                      11
    c_suite                      6
    vp                           4

  DEPARTMENT
    marketing                    33
    sales                        15
    executive                    11
    engineering                  6

  COUNTRY
    AU                           65

  EMAIL STATUS
    unverified                   35
    verified                     19
    guessed                      11

  INDUSTRY
    Computer Software            61
    Computer & Network Security  4
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Facets are pool-wide and carry no tenant overlay — the number of directors in the pool is the same for every org. The INDUSTRYblock only appears on the node-backed path; treat a missing block as “not available”, not as zero.

vxcli salesshift leads quota

Called live

The reveal meter for the current period.

Calls
GET {vxcloud}/api/v1/salesshift/leads/quota

No flags.

Shell
vxcli --no-color salesshift leads quota
Real output
  ▎ Reveal quota  ────────────────────────────────────────────────
    Used               2 / 200
    Allowance          200
    Remaining          198
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Remaining comes from the server rather than being derived client-side, so it stays right even when a spend lands between two reads.

vxcli salesshift leads reveal <pool-id>

Called live

Un-mask one pool person. Spends one reveal.

Calls
POST {vxcloud}/api/v1/salesshift/leads/reveal
Arguments
Exactly one <pool-id> — the id printed under a search row.
FlagTypeDefaultWhat it does
--yesboolfalseSkip the confirmation. This spends a reveal.
Shell
vxcli --no-color salesshift leads reveal 7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 --yes
Real output
  ! This will use up to 1 reveal(s) — you have 198 of 200 left this period.
  A person you have already revealed is free to reveal again.

  ▎ Revealed  ────────────────────────────────────────────────────
    Pool ID            7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55
    Email              [email protected]
    Phone              +61 2 5550 0142
    LinkedIn           https://www.linkedin.com/in/example-profile
    Reveals used       3 / 200
    Remaining          197

  Revealing does not make this person mailable — only `leads convert` creates a Contact.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

The cost line is printed before the spend, every time, even with --yes. If the meter cannot be read the line says the balance is unknown rather than inventing one.

vxcli salesshift leads save <pool-id>…

Called live

Copy pool rows into this tenant's saved leads. A snapshot taken now; spends nothing and unmasks nothing.

Calls
POST {vxcloud}/api/v1/salesshift/leads/save
Arguments
One or more <pool-id>. More than 200 is refused client-side before any request goes out.

No flags.

Shell
vxcli --no-color salesshift leads save \
  7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 \
  1978d19c-2fba-515b-85cc-9fb48034e9f7
Real output
  ▎ Saved to leads  ──────────────────────────────────────────────
    Requested          2
    Saved              2
    Already saved      0

  A saved lead is a snapshot. Addresses stay masked until revealed, and a
  saved lead is still not mailable — `leads convert` is the only route.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

vxcli salesshift leads show <pool-id>

Called live

Full detail for one pool person, their company, and your org's relationship to them. Masking still applies.

Calls
GET {vxcloud}/api/v1/salesshift/leads/pool/{pool_id}
Arguments
Exactly one <pool-id>.

No flags.

Shell
vxcli --no-color salesshift leads show 7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55
Real output (before the reveal above)
  ▎ Pool person  ─────────────────────────────────────────────────
    Pool ID            7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55
    Name               Sofia Ferreira
    Title              Founder
    Seniority          founder
    Department         executive
    Location           Melbourne, AU
    Score              62
    Email              s•••@kestreldata.example (masked — not revealed)
    Email status       unverified
    Phone              1 on file (not revealed)
    LinkedIn           on file (not revealed)
    First seen         2026-08-05T19:03:13.723501+00:00
    Last verified      —

  ▎ Company  ─────────────────────────────────────────────────────
    Name               Kestrel Data
    Domain             kestreldata.example
    Industry           Computer Software
    Employees          300
    Location           Sydney, AU
    Company ID         c93e17d5-6b28-4f90-a715-08c3b64de921

  ▎ Your relationship  ───────────────────────────────────────────
    Saved lead         not saved
    Saved status       —
    Converted contact  not converted
    Existing contact   none

  (masked) is not a real address — `vxcli salesshift leads reveal <pool-id>` spends one reveal.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Note how withheld data is described rather than hidden: 1 on file (not revealed) is a different statement from an empty field, and only one of the two is true here.

vxcli salesshift leads company <company-id>

Called live

Company detail plus its people, split into new prospects and people who are already your contacts.

Calls
GET {vxcloud}/api/v1/salesshift/leads/company/{company_id}
Arguments
Exactly one company pool id — printed by leads search --companies and by leads show.

No flags.

Shell
vxcli --no-color salesshift leads company 5b71e824-3c9d-4a16-92f0-6e83d1057ac4
Real output (people list trimmed)
  ▎ Company  ─────────────────────────────────────────────────────
    Pool ID            5b71e824-3c9d-4a16-92f0-6e83d1057ac4
    Name               Northwind Systems
    Domain             northwind.example
    Industry           Computer Software
    Employees          400
    Location           Sydney, AU
    Score              85
    Keywords           workforce scheduling, rostering, saas

  ▎ People (9 — 9 new, 0 already contacts)  ────────────────────

  NEW PROSPECTS
  Callum Reyes           Founder                         61
      6a3d9f57-8b40-5d61-ae92-7c14f80b25d3  c•••@northwind.example (masked — not revealed)
  Diego Carvalho         Marketing Director              57
      b17f4c98-52e0-5a73-8641-9d0e3b6af127  d•••@northwind.example (masked — not revealed)

  DEPARTMENTS
    marketing                7
    executive                2

  (masked) is not a real address — `vxcli salesshift leads reveal <pool-id>` spends one reveal.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

vxcli salesshift leads list

Called live

This tenant's saved leads. Still not mailable — convert first.

Calls
GET {vxcloud}/api/v1/salesshift/leads?limit=&status=
FlagTypeDefaultWhat it does
--statusstring""new, contacted, working, qualified, converted, disqualified.
--limitint100Clamped client-side to 1–500. The server declares a 500 ceiling with no floor, so a negative value would otherwise reach LIMIT -1 and 500.
Shell
vxcli --no-color salesshift leads list --limit 5
Real output
  ▎ Saved leads (4)  ─────────────────────────────────────────────

  NAME                   TITLE                    COMPANY            STATUS      SCORE
  Sofia Ferreira         Founder                  Kestrel Data       new            62
      3e91c7a5-0b64-4f28-9d13-7a205ce8b641  s•••@kestreldata.example (masked — not revealed)
  Mia Calderon           Founder                  Fjord Energy       new            61
      0b7f7b09-2fab-46da-99dd-4895ebb99d72  m•••@fjord.example (masked — not revealed)
  Tomo Nakamura          Founder                  Bluepine           converted      62
      6b2f8a14-77c3-4de9-b105-3ea9c5148d77  [email protected]  · converted
  Dana Keller            Marketing Director       Northwind Systems  converted      62
      c48a0e15-9d37-4b62-81fa-2069e4b7c530  [email protected]  · converted

  The id above is the LEAD id — use it with get / update / convert.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Two different id spaces

The id printed here is the lead id and belongs to your org. The id printed by leads search is the pool id and is global. Passing one where the other is expected produces a 404, not a wrong answer.

vxcli salesshift leads get <lead-id>

Called live

One saved lead, the live pool row behind it, and any drift between the two.

Calls
GET {vxcloud}/api/v1/salesshift/leads/{lead_id}
Arguments
Exactly one <lead-id> from leads list.

No flags.

Shell
vxcli --no-color salesshift leads get 6b2f8a14-77c3-4de9-b105-3ea9c5148d77
Real output
  ▎ Saved lead  ──────────────────────────────────────────────────
    Lead ID            6b2f8a14-77c3-4de9-b105-3ea9c5148d77
    Pool ID            4d0a72e6-3f81-5b09-9c25-6e17ab4083f2
    Name               Tomo Nakamura
    Title              Founder
    Company            Bluepine  bluepine.example
    Location           Brisbane, AU
    Status             converted
    Score              62
    Email              [email protected]
    Email status       guessed
    Notes              —
    Converted          aa38dd7e-c5bc-4a6a-a98b-ff08101a72c7

  ▎ Live pool row  ───────────────────────────────────────────────
    Active             true
    Revealed           true
    Title              Founder
    Company            Bluepine
    Email status       guessed
    Last verified      —
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

A saved lead is a frozen snapshot on purpose. The Live pool row block, and the drift list that follows it when the two disagree, is how you find out the world moved on before a bounce tells you.

vxcli salesshift leads update <lead-id>

Called live

Update a saved lead's status or notes. Only flags you actually passed are sent.

Calls
PATCH {vxcloud}/api/v1/salesshift/leads/{lead_id}
Arguments
Exactly one <lead-id>.
FlagTypeDefaultWhat it does
--statusstring""New status. Only sent if the flag was given.
--notesstring""Replaces the notes. Pass an empty string to clear them.
Shell
vxcli --no-color salesshift leads update 3e91c7a5-0b64-4f28-9d13-7a205ce8b641 \
  --status working \
  --notes "Intro via the Melbourne fintech meetup — wants a demo in September."
Real output
  ▎ Lead updated  ────────────────────────────────────────────────
    Lead ID            3e91c7a5-0b64-4f28-9d13-7a205ce8b641
    Name               Sofia Ferreira
    Status             working
    Notes              Intro via the Melbourne fintech meetup — wants a demo in September.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Passing neither flag is refused before the request: ✗ nothing to update — pass --status and/or --notes, exit 1.

vxcli salesshift leads convert <lead-id>

Called live

Saved lead → Contact. This is the only way a record becomes mailable.

Calls
POST {vxcloud}/api/v1/salesshift/leads/{lead_id}/convert
Arguments
Exactly one <lead-id>. The lead needs a revealed address.

No flags.

Shell
vxcli --no-color salesshift leads convert 3e91c7a5-0b64-4f28-9d13-7a205ce8b641
Real output
  ▎ Converted to contact  ────────────────────────────────────────
    Contact ID         694bd7ad-b8c6-41b9-975f-86ecfef177a1
    Reused existing    false

  This contact is now mailable. The lead row is kept as the audit trail.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Converting a lead that was already converted is not an error — it prints Already converted with the existing contact id and exits 0.

vxcli salesshift leads bulk-convert <lead-id>…

Called live

Convert many saved leads. Every id is accounted for, including the ones that could not be converted.

Calls
POST {vxcloud}/api/v1/salesshift/leads/bulk-convert
Arguments
One or more <lead-id>.

No flags.

Shell
vxcli --no-color salesshift leads bulk-convert \
  3e91c7a5-0b64-4f28-9d13-7a205ce8b641 \
  0b7f7b09-2fab-46da-99dd-4895ebb99d72
Real output
  ▎ Bulk convert  ────────────────────────────────────────────────
    Requested          2
    Converted          0
    Already converted  1
    Skipped — no email 1

  A lead with no revealed address cannot be converted — reveal it first.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

When the buckets do not add up to the number of ids you passed, the command says so — the remainder were not your leads, or do not exist.

vxcli salesshift leads convert-from-pool <pool-id>…

Called live

Save, reveal if needed, and convert straight from the pool. Spends quota unless --no-reveal.

Calls
POST {vxcloud}/api/v1/salesshift/leads/convert-from-pool
Arguments
One or more <pool-id>. More than 200 is refused client-side.
FlagTypeDefaultWhat it does
--no-revealboolfalseSpend nothing: convert only rows already revealed, and report the rest as skipped_no_quota.
--yesboolfalseSkip the confirmation. This spends reveals unless --no-reveal is also set.
Shell
vxcli --no-color salesshift leads convert-from-pool \
  8a28e51d-8811-5fc2-9819-c6d75cbb1310 \
  be6215a3-54cd-58fe-a36e-a41fcb5a95f6 \
  --no-reveal --yes
Real output
  ! This will NOT spend any reveals.
  A person you have already revealed is free to reveal again.
  Only already-revealed rows convert; the rest are reported as skipped_no_quota.
  Converting creates 2 mailable Contact(s).

  ▎ Converted from pool  ─────────────────────────────────────────
    Requested          2
    Converted          0
    Revealed now       0
    Already converted  0
    Skipped — no quota 2
    Skipped — no email 0
    Skipped — erased   0
    Contact IDs        0
    Reveals used       3 / 200
    Remaining          197
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Every bucket is printed every time. Rendering only Converted would hide a partial spend, which is the fastest way to make a meter untrustworthy. When the allowance runs out mid-batch the rows that needed a reveal come back as skipped_no_quota and were not charged.

vxcli salesshift leads enrich <domain>

Called live

Crawl a company's own website and fold what it finds into the shared pool.

Calls
POST {vxcloud}/api/v1/salesshift/leads/enrich
Arguments
A bare domain (a company not yet in the pool is created), or nothing plus --company-id.
FlagTypeDefaultWhat it does
--company-idstring""Enrich a company already in the pool, by its pool id, instead of passing a domain.
Shell
vxcli --no-color salesshift leads enrich example.com
Real output
  Crawling — this reads several pages and can take a minute.

  ▎ Enrichment  ──────────────────────────────────────────────────
    Pages read         1
    Company            created in the pool
    Fields filled      company created, keywords
    Addresses found    0
    People added       0
    Already on file    0

  Everything found is unverified — `leads convert` still gates mailability.
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

Run against example.com, a single static page, so this is about the floor of what a crawl returns. Pages read is the crawled counter and Fields filled is the changed array; both scale up on a real marketing site. Company and Fields filled only print when the crawl actually created or changed something, and if Pages read comes back 0 the command prints the server’s own explanation — blocked, unreachable and empty are different problems — and stops.

The only command here that writes to the shared pool

It fills gaps and never overwrites an existing description, keyword set or address. It checks the erasure list before every insert, so a crawl cannot resurrect someone who asked to be forgotten. Shared mailboxes (sales@, info@, announce@) are not people and are not ingested. Everything it stores is recorded as unverified — finding a string on a web page is not verification — and it spends no reveal quota.

vxcli salesshift leads erasure

Not exercised here

Right to be forgotten. Global across every tenant on the platform, and irreversible.

Calls
POST {vxcloud}/api/v1/salesshift/leads/erasure
FlagTypeDefaultWhat it does
--emailrequiredstring""The address to erase. Missing or blank exits 1 before any request.
--reasonstringgdpr_erasureReason recorded with the erasure.
--notestring""Free-text note for the erasure record.
--yesboolfalseSkip the confirmation. This erases the person for every tenant, irreversibly.

Not executed while writing this page

This is the one command in the group with no pasted output. Running it would deactivate a real person in the shared pool for everytenant, strip their address from every org’s saved leads, and record a hash so no future crawl can re-add them. There is no undo, so nothing below was demonstrated — it is read from the source.

From the source: the command prints the four-line warning below, asks Erase this person everywhere? [y/N] unless --yes is set, then posts {email, reason, note?} and reports pool_rows_erased, saved_leads_flagged and already_recorded.

The confirmation text, from the source — not a captured run
  ! Erasure is GLOBAL and IRREVERSIBLE.
  It removes this person for EVERY tenant on the platform, not just yours,
  strips the address from every saved lead everywhere, and blocks re-crawling.
  There is no undo.
  Subject: [email protected]
  ? Erase this person everywhere? [y/N]

The missing-flag guard was exercised: running leads erasure with no --email printed ✗ --email is required and exited 1 without contacting the server.

vxcli salesshift leads searches list

Called live

This org's saved searches.

Calls
GET {vxcloud}/api/v1/salesshift/lead-searches

No flags.

Shell
vxcli --no-color salesshift leads searches list
Real output
  ▎ Saved searches (1)  ──────────────────────────────────────────
  AU founders with an address  e8176c8a-7798-4971-ba47-7871763967a5
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

vxcli salesshift leads searches save

Called live

Store the current filter flags under a name. Filters only — a cursor is a position inside one result set and is never saved.

Calls
POST {vxcloud}/api/v1/salesshift/lead-searches
FlagTypeDefaultWhat it does
--namerequiredstring""Name for the saved search. Missing or blank exits 1.
--qstring""Free text over name, title and company.
--titlerepeatablestringTitle contains. Repeat to OR several.
--exclude-titlerepeatablestringTitle must NOT contain. Repeat to exclude several.
--seniorityrepeatablestringOne of founder c_suite vp director manager senior entry.
--departmentrepeatablestringOne of engineering sales marketing finance hr ops legal executive.
--countryrepeatablestringISO-2 country code, e.g. AU. Upper-cased server-side.
--industryrepeatablestringIndustry, e.g. "Computer Software".
--email-statusrepeatablestringverified unverified guessed catch_all invalid.
--employeesrepeatablestringCompany size band, e.g. 51-200, 5000+.
--domainrepeatablestringCompany domain, e.g. northwind.example.
--keywordrepeatablestringCompany keyword, substring match — "saas" also matches "saas management".
--min-scoreint0Minimum quality score. 0 means no constraint.
--has-emailboolunsetOnly rows where an address exists. That is not permission to read one — it is still masked until revealed. Tri-state: leave it off for no constraint, --has-email=false to require rows with no address.
--has-phoneboolunsetOnly rows where a phone number exists. Tri-state, same as above.
Shell
vxcli --no-color salesshift leads searches save \
  --name "AU founders with an address" \
  --country AU --seniority founder --has-email
Real output
  ▎ Search saved  ────────────────────────────────────────────────
    ID                 e8176c8a-7798-4971-ba47-7871763967a5
    Name               AU founders with an address
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

There is no command to delete or update a saved search in this group.

Billing — the plan and the free tier

What this workspace pays SalesShift. Not to be confused with quotes, invoices and subscriptions, which are money your customers pay you.

Twelve commands. The nine Stripe-facing ones — plans, subscription, invoices, events, checkout, portal, change, cancel, resume — are in the generated reference with their exact flags. The three below exist because of the Self-Hosted plan, which is free, permanent, and runs on the tenant’s own node rather than ours — so “what am I paying for” and “what am I allowed to do” stopped being the same question.

vxcli salesshift billing entitlements

Called live

The resolved plan, who runs each capability, and every allowance. The command to run after something answered 402.

Calls
GET {vxcloud}/api/v1/salesshift/billing/entitlements
Arguments
Aliased ent and allowance.

No flags.

Shell
vxcli --no-color salesshift billing entitlements
Real output — a comped Organization workspace
  Organization  ACTIVE
  · organization · source comp · 25 seat(s)

  Who runs what
   ✓ compute   SalesShift runs the prospect pool, the crawlers and the agents
   ✓ sending   SalesShift runs the outbound mail path
   ✓ ai        SalesShift runs the model and the key it bills to

  Allowance — workspace total per month, null is unlimited
   · reveals     2500000
   · emails      unlimited
   · ai          500000
   · mailboxes   unlimited
   · contacts    unlimited
   · users       unlimited
Real output, captured 2026-08-13 against http://localhost:8741. Counts move as the system is used — yours will differ.

Who runs what is three booleans the API calls managed.compute, managed.sending and managed.ai. They are not permissions — they say whose bill a capability lands on. A there means you run it, which is the whole reason the plan is free.

The allowance figures are the workspace total: on a paid plan the per-seat quota has already been multiplied by the seat count, which is why a 25-seat Organization shows 2,500,000 reveals rather than the 100,000 printed by billing plans.

A zero here is not always a limit

On Self-Hosted, allowance.emails and allowance.ai come back as 0. That does not mean the workspace may not send — it means SalesShift is not the one sending, so there is nothing to meter. The command prints not metered — you provide it, so we do not count it for any row whose managed flag is false, rather than the misleading number. If you read the API directly, read managed before you read allowance.

--output json emits the response unchanged — the same payload, with none of the rendering above applied.

Real output — vxcli --output json salesshift billing entitlements
{
  "allowance": {
    "ai": 500000,
    "contacts": null,
    "emails": null,
    "mailboxes": null,
    "reveals": 2500000,
    "users": null
  },
  "is_free": false,
  "managed": {
    "ai": true,
    "compute": true,
    "sending": true
  },
  "plan_code": "organization",
  "plan_name": "Organization",
  "seats": 25,
  "self_hosted": {
    "node_host": null,
    "ready": true,
    "required": false,
    "verified_at": null
  },
  "source": "comp",
  "status": "active"
}
Real output, captured 2026-08-13 against http://localhost:8741. Counts move as the system is used — yours will differ.

vxcli salesshift billing node

Called live

The node a self-hosted workspace runs itself. With no subcommand it reports the current state — and the tenant id a node must claim before it can be registered.

Calls
GET {vxcloud}/api/v1/salesshift/billing/self-hosted
Arguments
None. Aliased self-hosted. This is a command that also has subcommands, so --help shows two usage lines.

No flags.

Shell
vxcli --no-color salesshift billing node
Real output — a workspace on a managed plan
  No node registered — this plan runs on SalesShift infrastructure, so none is needed.

  A node must report this workspace id before it can be registered:
    TENANT_ID=92efb9b0-6785-468a-80d7-ceb5df400168
  · image ghcr.io/vxcloud/vxnode:latest · probed at /health
Real output, captured 2026-08-13 against http://localhost:8741.

The TENANT_IDblock prints whether or not this plan needs a node. It is the one fact an operator cannot read off the box itself, and the answer to “which id does this workspace expect?” should not depend on what the workspace is paying today.

A workspace name is sometimes accepted as well — real nodes are provisioned with TENANT_ID=<name> — but only when that name is unique across every organization. When it is not, the command prints just the UUID, and the name is refused. That is the case above: three organizations share the name joelwembo, so the also accepted line is absent.

vxcli salesshift billing node register <host>

Called live

Register a node, once it has proved which workspace it belongs to. The control plane calls the node — you are not typing a hostname into a text field.

Calls
POST {vxcloud}/api/v1/salesshift/billing/self-hosted/node
Arguments
Exactly one: the base URL of the node. HTTPS is required; http:// is accepted only for localhost and 127.0.0.1.

No flags.

The server fetches <host>/healthand requires the answer to report this workspace’s tenant id. Only then is the host written down, together with the verification time and a fingerprint of <claimed-id>@<version>.

This command deliberately does not use the group’s shared error printer. Each failure needs a different next action, and ✗ HTTP 403 — <detail> on one line buries the tenant id the operator now has to go and set on the box.

Real output — all three refusals, each exit 1
$ vxcli --no-color salesshift billing node register node1.vxcloud.io

  Not registered — the node did not prove it belongs to this workspace.
  That node identifies as another workspace. Set TENANT_ID=92efb9b0-6785-468a-80d7-ceb5df400168 in its environment and restart it. (Your workspace name 'joelwembo' is shared with another workspace, so only the id above is accepted here.)
  Nothing was recorded, and the node itself was not modified.
exit 1

$ vxcli --no-color salesshift billing node register http://leads.example.com

  Refused — the node did not identify a tenant, or the address is not HTTPS.
  The node must be reachable over HTTPS.
exit 1

$ vxcli --no-color salesshift billing node register https://nope.invalid-host-for-test.io

  The node did not answer.
  Could not reach https://nope.invalid-host-for-test.io/health — HTTPSConnectionPool(host='nope.invalid-host-for-test.io', port=443): Max retries exceeded with url: /health (Caused by NameResolutionError("…Failed to resolve…"))
  It has to be reachable from the control plane, not only from your laptop.
exit 1
Real output, captured 2026-08-13 against http://localhost:8741.

Running billing node again afterwards showed the workspace still unregistered, which is the point: a refused registration records nothing and does not touch the node either.

StatusHeadlineWhat it means
400Refused — the node did not identify a tenant, or the address is not HTTPS.Either the address was plaintext, or the node answered without a tenant_id. Run live, above.
403Not registered — the node did not prove it belongs to this workspace.The node answered, and named a different workspace. The server’s own detail follows, carrying the id to set; below that, Nothing was recorded, and the node itself was not modified. Run live, above.
502The node did not answer.The probe failed outright — DNS, TLS or a firewall. Run live, above.

How the 403 was reached

It needs a node that answers /healthwith somebody else’s tenant id, and the only ones available on this deployment are real workspaces’ nodes — so the capture above points at one. That is safe precisely because the handshake refuses it: the probe is a GET /health, the node is not touched, and GET /billing/self-hosted read afterwards still answered host: null. What was not run is the accepting branch.

vxcli salesshift billing node detach

Not exercised here

Forget the registered node. Clears the host, the verification time and the fingerprint.

Calls
DELETE {vxcloud}/api/v1/salesshift/billing/self-hosted/node
Arguments
None. Aliased unregister and remove.
FlagTypeDefaultWhat it does
--yesboolfalseSkip the confirmation prompt. Without it the command asks first.

Sending, crawling and agent work stop until another node is registered. Nothing falls back to SalesShift infrastructure — on this plan it never ran there, which is why the command confirms before it acts.

vxcli salesshift billing activate

Not exercised here

Move this workspace onto a free plan. No card, no Stripe, no $0 price object.

Calls
POST {vxcloud}/api/v1/salesshift/billing/activate
FlagTypeDefaultWhat it does
--planstring"self_hosted"Free plan code to activate. Only plans flagged free are accepted — a paid code is refused here rather than quietly granted.

It also refuses to downgrade a live plan that is paid or granted. That has to go through billing cancel, which tells Stripe when there is a Stripe to tell — losing a plan by accident hurts the same whether it was bought or given.

On success it prints the new plan and, when that plan needs a node and none is registered, the one line that matters next: This plan runs on your own node — nothing sends until one is registered.

The counterpart refusals

billing checkout refuses a free plan and billing change refuses a free target, for the same reason in reverse: moving to free is a cancellation, and a cancellation has to reach Stripe. The three commands only make sense read together.

Errors and exit codes

Two exit codes. 0 on success, 1 on any failure — including a client-side refusal that never reached the network.

A mistyped subcommand exits 0

vxcli salesshift nope prints the group help and exits 0, not 1. A script that branches on the exit status alone will read a typo as success. Verified.

The leadscommands map status codes to sentences rather than echoing “HTTP 402”. Two of those mappings exist because the wrong reaction is expensive: a 402 is a refusal that charged you nothing, and a 410 is terminal rather than an outage to retry.

StatusWhat the CLI printsWhat it means
402✗ reveal allowance spent — nothing was charged for this attempt.The meter is empty. Nothing was billed. It also prints Meter: vxcli salesshift leads quota.
410✗ removed at the person's request.Terminal. Retrying will not bring it back — the command says so explicitly.
404✗ not found: <server detail>The server’s own wording is passed through, because that is what separates “not in the pool” from “not your lead”.
400✗ rejected: <server detail>Followed by the two usual causes: a cursor reused after a re-sort, or a convert on a lead with no revealed address.
401 / 403✗ not authorized — run `vxcli auth login`Expired or missing credential.
other✗ <action> failed (HTTP <code>): <detail>Falls back to no detail returned when the body carries none.

Three of these were exercised directly:

Real output
$ vxcli --no-color salesshift leads show 00000000-0000-0000-0000-000000000000
✗ not found: Person not found in the pool
exit 1

$ vxcli --no-color salesshift leads search --cursor not-a-real-cursor --limit 2
✗ rejected: Malformed cursor
    Usual causes       a cursor reused after changing the sort or filters,
                       or a convert on a lead with no revealed address
exit 1

$ HOME=/tmp/empty vxcli --no-color salesshift leads quota
✗ quota: not authenticated — run `vxcli auth login` first
exit 1

$ HOME=/tmp/empty vxcli --no-color salesshift stats
✗ stats failed (HTTP 0): not authenticated — run `vxcli auth login` first
exit 1
Real output, captured 2026-08-07 against http://127.0.0.1:8741 and http://127.0.0.1:8744. Counts move as the system is used — yours will differ.

The last two show the two different shapes: the leads commands go through the mapping table above, while stats and email use a simpler formatter — which is why an un-authenticated stats reports HTTP 0, the code for “no request was made”.

One command has a third shape. billing node register maps 400, 403 and 502 to three multi-line messages of its own, because each of them leaves the operator with a different thing to go and fix and the one-line form buries it.

Full command reference

Every group the binary exposes. The five above are covered in prose with real terminal output; the rest are listed here with their exact flags, defaults and help text.

Generated, not written

This section is built by walking vxcli salesshift <group> <command> --help on the compiled binary and rendering the result. A command that is not in the binary cannot appear here, and one that is added cannot be silently missed — which is the only way a 229-command reference stays true.
GroupCommandsWhat it covers
analytics10The numbers behind the dashboards
billing12Your SalesShift plan — pricing, seats, invoices
calendar10Meetings — agenda, events and invitations
campaigns11Email campaigns and their reports
companies4Accounts — the companies behind your contacts
contacts13Your CRM contacts — the only records that are mailable
contracts7Contracts — draft, send for signature, track and audit
conversations2Reply threads — what came back from your sends
deals8Pipelines and deals — the revenue board
deliverability13Inbox health, domain auth and placement — why mail lands or does not
email2SalesShift email operations
goals3Quota targets and the leaderboard
invoices11Invoices — issue, send, chase and record payment
leads16Prospect pool — search, reveal, save, convert (leads are NOT mailable until converted)
lists6Contact lists — the audiences campaigns and sequences send to
opportunities8The shared signal pool — buying and hiring signals
quotes10Priced proposals — draft, get them approved internally, send
reports8Saved and ad-hoc reports over the CRM datasets
seo12Site audits, keyword tracking and rank checks
sequences17Multi-step outbound sequences with delays, A/B variants and stop rules
settings5Workspace settings — suppressions, team, integrations, mailboxes
social5Social distribution — one post, every network, in parallel
stats1SalesShift dashboard stats (contacts, deals, email funnel)
subscriptions6Your customers' recurring revenue (NOT your own SalesShift plan)
tasks5Tasks — description, due date, owner and target goal
webmaster4Inspect a live URL, robots.txt and sitemap.xml
worker1Tenant email-worker operations
workflows11Automation workflows — the /automations canvas, from a terminal

vxcli salesshift analytics

10 commandsaliases: stats-detail

The numbers behind the dashboards

vxcli salesshift analytics activity

Activity timeline

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics campaigns

Campaign performance

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics contract-cycle

Contract cycle

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics email

Email analytics

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics engagement

Engagement

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics funnel

Conversion funnel

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics health

Activity health

vxcli salesshift analytics overview

Overview

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics sales

Sales analytics

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift analytics timeseries

Time series

FlagTypeDefaultWhat it does
--daysint30Window in days (1–365)

vxcli salesshift billing

12 commandsdetailed section abovealiases: plan, subscription

Your SalesShift plan — pricing, seats, invoices

What this workspace pays SalesShift.

Not to be confused with `vxcli salesshift` quote-to-cash commands, which concern money YOUR customers pay YOU.

vxcli salesshift billing activate

Move this workspace onto a free plan — no card, no Stripe

Activates a plan flagged free. A paid code is refused here rather than quietly granted, and no $0 Stripe price is ever created.

It also refuses to downgrade a live paid OR granted plan: that has to go through `billing cancel`, which tells Stripe when there is a Stripe to tell. Losing a plan by accident hurts the same whether it was bought or given.

FlagTypeDefaultWhat it does
--planstring"self_hosted"Free plan code to activate (only plans flagged free are accepted)

vxcli salesshift billing cancel

Cancel the subscription

FlagTypeDefaultWhat it does
--at-period-endbooltrueKeep access until the period closes (false cancels immediately)
--yesboolSkip the confirmation prompt

vxcli salesshift billing change

Change plan and/or seat count

FlagTypeDefaultWhat it does
--planstringNew plan code
--seatsintNew seat count

vxcli salesshift billing checkout

Open a Stripe Checkout session for a plan

Returns a hosted Stripe URL. Nothing is charged until it is completed there.

FlagTypeDefaultWhat it does
--planstringstarter | professional | organization
--seatsint1Number of seats

vxcli salesshift billing entitlements

What this workspace may actually do right now

The command to run after something came back 402 Payment Required.

It shows the resolved plan, who runs the compute, the sending and the model, and every allowance. A null allowance is unlimited.

On Self-Hosted, emails and AI are not an allowance of zero — they are not ours to meter, because the mail leaves your mailbox over your IP and the model call bills to your key. The managed flags are what say so, and this command prints them rather than the misleading number.

vxcli salesshift billing events

Billing history for this workspace

vxcli salesshift billing invoices

List invoices from Stripe

vxcli salesshift billing node

The node a self-hosted workspace runs itself

On Self-Hosted the tenant's own vxnode does the sending, the crawling and the agent work that we do for paid plans.

Registration is a handshake, not a text field: the control plane calls the node's /health and requires it to report this workspace's tenant id before the host is written down. Run with no subcommand to see the current state.

vxcli salesshift billing node detach

Forget the registered node

Clears the host, the verification time and the fingerprint. Sending, crawling and agent work stop until another node is registered — nothing falls back to our infrastructure, because on this plan it never ran there.

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift billing node register <host>

Register your node, once it proves which workspace it belongs to

The control plane calls <host>/health and requires the answer to carry this workspace's tenant id. A node that answers with a different id is refused, and that refusal is the point of the command rather than an edge case — it is what stops one workspace pointing us at another's node.

HTTPS is required; http:// is accepted only for localhost.

vxcli salesshift billing plans

List the published plans and what each one includes

vxcli salesshift billing portal

Get a Stripe billing-portal URL (cards, receipts, cancellation)

vxcli salesshift billing resume

Clear a pending cancellation

vxcli salesshift billing subscription

Show this workspace's current plan, seats and allowance

vxcli salesshift calendar

10 commandsaliases: cal

Meetings — agenda, events and invitations

vxcli salesshift calendar agenda

What is coming up

vxcli salesshift calendar calendars

The calendars in this workspace

vxcli salesshift calendar create

Schedule a meeting and mail the invitations

Guests are recorded either way; --no-invites only decides whether they are emailed. Times are RFC3339, e.g. 2026-08-20T15:00:00Z.

FlagTypeDefaultWhat it does
--contactstringContact id
--endstringEnd (RFC3339)
--guestsstringGuest emails, comma separated
--locationstringWhere
--no-invitesboolRecord guests without mailing them
--startstringStart (RFC3339)
--titlestringMeeting title
--urlstringMeeting link

vxcli salesshift calendar delete <event-id>

Cancel an event

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift calendar duplicate <event-id>

Copy an event

vxcli salesshift calendar events

Events in a window

FlagTypeDefaultWhat it does
--fromstringWindow start (RFC3339)
--tostringWindow end (RFC3339)

vxcli salesshift calendar export

Download the calendar as an .ics file

FlagTypeDefaultWhat it does
--outstringWhere to write the .ics

vxcli salesshift calendar invite <event-id>

Invite more guests to an existing event

FlagTypeDefaultWhat it does
--guestsstringGuest emails, comma separated

vxcli salesshift calendar invites <event-id>

Who was invited and how they replied

vxcli salesshift calendar show <event-id>

One event and its guest list

vxcli salesshift campaigns

11 commandsaliases: campaign

Email campaigns and their reports

vxcli salesshift campaigns audience-preview

How many people a campaign would actually reach

Resolves contacts and lists the same way a send does, so the count here already excludes suppressed and unsubscribed addresses. Worth running before a blast rather than discovering the gap in the report afterwards.

FlagTypeDefaultWhat it does
--contactsstringContact ids
--listsstringList ids

vxcli salesshift campaigns create

Create a campaign from a list of contact ids

Builds the campaign and, with --send, delivers it immediately.

Sender: omit --from-email to use the org's default integration (its configured From and Reply-To are used as-is). Setting --from-email stamps that address in the From header — make sure the sending domain actually authorises it, or SPF/DKIM alignment breaks and the mail lands in spam.

FlagTypeDefaultWhat it does
--bodystringHTML body
--body-filestringRead the HTML body from a file
--contactsstringComma-separated contact ids
--from-emailstringFrom address (default: the org's default integration)
--from-namestringFrom display name
--listsstringComma-separated list ids
--namestringCampaign name (required)
--reply-tostringReply-To address
--sendboolSend immediately after creating
--subjectstringSubject line — merge tags allowed

vxcli salesshift campaigns delete <campaign-id>

Delete a campaign and its recipient rows

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift campaigns list

List campaigns

vxcli salesshift campaigns report <campaign-id>

Full report — metrics and every tracked recipient

vxcli salesshift campaigns seed-templates

Install the starter templates into this workspace

vxcli salesshift campaigns send <campaign-id>

Send (or re-send) a campaign

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift campaigns senders

Which addresses this workspace can send from

A campaign can only send from a server it authenticates as. This is the list that --from-email is validated against.

vxcli salesshift campaigns templates

The saved template gallery

vxcli salesshift campaigns test-send <campaign-id>

Send one copy to yourself before the real blast

FlagTypeDefaultWhat it does
--tostringOverride the test recipient

vxcli salesshift campaigns unschedule <campaign-id>

Cancel a scheduled send and return the campaign to draft

vxcli salesshift companies

4 commandsaliases: company, accounts

Accounts — the companies behind your contacts

vxcli salesshift companies create

Create a company

FlagTypeDefaultWhat it does
--domainstringPrimary domain
--employeesintEmployee count
--industrystringIndustry
--namestringCompany name

vxcli salesshift companies delete <company-id>

Delete a company

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift companies list

List companies

FlagTypeDefaultWhat it does
--limitint25Rows to return
--qstringSearch name or domain

vxcli salesshift companies update <company-id>

Update a company

FlagTypeDefaultWhat it does
--domainstringPrimary domain
--employeesintEmployee count
--industrystringIndustry
--namestringCompany name

vxcli salesshift contacts

13 commandsaliases: contact

Your CRM contacts — the only records that are mailable

Contacts are converted leads. Unlike a pool row, a contact already owns its email and phone, so nothing here is masked and nothing costs a reveal.

vxcli salesshift contacts create

Create a contact

FlagTypeDefaultWhat it does
--companystringCompany name
--emailstringEmail address
--firststringFirst name
--laststringLast name
--phonestringPhone number
--titlestringJob title

vxcli salesshift contacts delete <id>

Delete a contact

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift contacts email <contact-id>

Send a tracked one-off email to a contact

Sends through the same pipeline the app uses: suppression gate, sending pool, open pixel and unsubscribe footer. The reply lands in the contact's conversation thread, so this is also how you reply from a terminal.

FlagTypeDefaultWhat it does
--bodystringHTML body
--body-filestringRead the HTML body from a file
--from-emailstringOverride the From address
--reply-tostringOverride Reply-To
--subjectstringSubject line

vxcli salesshift contacts enrich

Fill in missing company, title and social data

FlagTypeDefaultWhat it does
--contactsstringContact ids to enrich (default: everything unenriched)

vxcli salesshift contacts enrollments <contact-id>

Every sequence and workflow this contact is in

vxcli salesshift contacts import

Bulk-create contacts from a JSON file

The file is a JSON array of contact objects, each needing at least "email". Duplicates are matched on address and reported as skipped rather than creating a second record for the same person.

FlagTypeDefaultWhat it does
--filestringJSON array of contacts

vxcli salesshift contacts list

List contacts

FlagTypeDefaultWhat it does
--has-emailboolOnly contacts with an address
--limitint25Rows to return (max 100)
--min-scoreintMinimum total score
--qstringSearch name, email, company or title
--stagestringLifecycle stage

vxcli salesshift contacts lists

Contact lists in this workspace

vxcli salesshift contacts membership <contact-id>

Which lists this contact is on

vxcli salesshift contacts note <contact-id>

Attach a note to a contact

FlagTypeDefaultWhat it does
--textstringNote body

vxcli salesshift contacts rescore <contact-id>

Recompute fit and intent for one contact

vxcli salesshift contacts show <id>

One contact in full, with its recent activity

vxcli salesshift contacts update <id>

Update a contact

FlagTypeDefaultWhat it does
--companystringCompany name
--emailstringEmail address
--firststringFirst name
--laststringLast name
--phonestringPhone number
--stagestringLifecycle stage
--titlestringJob title

vxcli salesshift contracts

7 commandsaliases: contract

Contracts — draft, send for signature, track and audit

Everything on your side of a contract is scriptable. The one thing that is not is the signature itself: signing happens on a tokenised page in the counterparty's browser, under an ESIGN/UETA consent disclosure, and a signature produced by a CLI would not be one. So there is no `sign` command here by design — but drafting, sending, chasing, auditing and downloading the executed PDF all are.

vxcli salesshift contracts audit <contract-id>

The signing audit trail — who did what, when, from where

vxcli salesshift contracts create

Draft a contract from HTML

FlagTypeDefaultWhat it does
--body-filestringHTML body file
--dealstringDeal id
--party-astringYour side's name
--party-a-emailstringYour side's email
--party-bstringCounterparty name
--party-b-emailstringCounterparty email
--titlestringContract title

vxcli salesshift contracts delete <contract-id>

Delete a contract

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift contracts list

List contracts and where each one stands

vxcli salesshift contracts pdf <contract-id>

Download the contract PDF (executed copy once signed)

FlagTypeDefaultWhat it does
--outstringWhere to write the PDF

vxcli salesshift contracts send <contract-id>

Send for signature

Emails the counterparty a tokenised signing link. That page is where the signature is captured — this command starts the process, it does not complete it. Track progress with `contracts audit`.

vxcli salesshift contracts upload

Upload an existing PDF as a contract

FlagTypeDefaultWhat it does
--dealstringDeal id
--filestringPDF to upload
--party-astringYour side's name
--party-a-emailstringYour side's email
--party-bstringCounterparty name
--party-b-emailstringCounterparty email
--titlestringContract title

vxcli salesshift conversations

2 commandsaliases: inbox, threads

Reply threads — what came back from your sends

vxcli salesshift conversations list

Every thread with a reply

vxcli salesshift conversations show <contact-id>

The full thread with one contact

Reply with `vxcli salesshift contacts email <contact-id> --subject … --body …`.

vxcli salesshift deals

8 commandsaliases: deal, pipeline

Pipelines and deals — the revenue board

vxcli salesshift deals create

Create a deal (defaults to the first stage of the default pipeline)

FlagTypeDefaultWhat it does
--amountfloatDeal value
--closestringExpected close date (YYYY-MM-DD)
--companystringCompany id
--contactstringContact id
--currencystring"USD"Currency code
--namestringDeal name
--pipelinestringPipeline id
--stagestringStage id
--tagsstringComma-separated tags

vxcli salesshift deals delete <deal-id>

Delete a deal

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift deals forecast

Weighted pipeline forecast

vxcli salesshift deals forecast-category <deal-id>

Set a deal's forecast category (commit, best-case, pipeline, omitted)

FlagTypeDefaultWhat it does
--categorystringcommit | best_case | pipeline | omitted

vxcli salesshift deals list

List deals

FlagTypeDefaultWhat it does
--pipelinestringPipeline id
--statusstringopen | won | lost

vxcli salesshift deals move <deal-id>

Move a deal to another stage

Stage ids come from `vxcli salesshift deals pipelines`.

Moving into a won/lost stage is what closes a deal — the server derives the status from the stage, so there is no separate "close" verb to forget.

FlagTypeDefaultWhat it does
--stagestringTarget stage id (required)

vxcli salesshift deals pipelines

Pipelines and their stages

vxcli salesshift deals update <deal-id>

Update a deal

FlagTypeDefaultWhat it does
--amountfloatDeal value
--closestringExpected close date (YYYY-MM-DD)
--companystringCompany id
--contactstringContact id
--currencystring"USD"Currency code
--lost-reasonstringWhy it was lost
--namestringDeal name
--statusstringopen | won | lost

vxcli salesshift deliverability

13 commandsaliases: deliv

Inbox health, domain auth and placement — why mail lands or does not

vxcli salesshift deliverability alerts

Open deliverability alerts

FlagTypeDefaultWhat it does
--historyboolShow resolved alerts too, not just open ones

vxcli salesshift deliverability domain <domain>

Full auth record check for one domain

vxcli salesshift deliverability domains

SPF / DKIM / DMARC across your sending domains

vxcli salesshift deliverability inboxes

Per-inbox warmup state and daily volume

vxcli salesshift deliverability pause <inbox-id>

Stop sending from one mailbox

vxcli salesshift deliverability placement-tests

Past inbox-placement results

vxcli salesshift deliverability policy <inbox-id>

Change one mailbox's sending policy (pool membership, cap, gap)

FlagTypeDefaultWhat it does
--daily-capintMax sends per day
--in-poolbooltrueInclude in the sending pool
--send-gapintSeconds between sends

vxcli salesshift deliverability resume <inbox-id>

Resume sending from one mailbox

vxcli salesshift deliverability run-placement-test

Send a probe to the seed list and report where it landed

Placement is only claimed for seeds that are mailboxes this workspace has connected — reading the destination folder is the only way to know. Other seeds are recorded as sent with no placement, rather than guessed at.

FlagTypeDefaultWhat it does
--inboxstringProbe from this inbox

vxcli salesshift deliverability seed-add

Add a seed inbox

FlagTypeDefaultWhat it does
--emailstringSeed address

vxcli salesshift deliverability seed-list

The seed inboxes used for placement tests

vxcli salesshift deliverability seed-remove <seed-id>

Remove a seed inbox

vxcli salesshift deliverability settings

Warmup and throttling policy

vxcli salesshift email

2 commandsdetailed section above

SalesShift email operations

vxcli salesshift email list

List tracked emails and their engagement state

FlagTypeDefaultWhat it does
--statusstringFilter by status (sent, opened, replied, bounced, …)

vxcli salesshift email send

Send a tracked email (suppression gate, caps, tenant node worker)

FlagTypeDefaultWhat it does
--bodystringHTML body
--body-filestringRead HTML body from a file
--subjectstringEmail subject (merge tags like {{first_name}} allowed)
--tostringRecipient email address

vxcli salesshift goals

3 commands

Quota targets and the leaderboard

vxcli salesshift goals create

Set a goal

FlagTypeDefaultWhat it does
--endstringPeriod end (YYYY-MM-DD)
--metricstringMetric key
--ownerstringWhose goal (default: you)
--periodstring"month"month | quarter | year
--startstringPeriod start (YYYY-MM-DD)
--targetintTarget value

vxcli salesshift goals leaderboard

Who is ahead

FlagTypeDefaultWhat it does
--endstringPeriod end (YYYY-MM-DD)
--startstringPeriod start (YYYY-MM-DD)

vxcli salesshift goals list

Goals and progress against them

vxcli salesshift invoices

11 commandsaliases: invoice

Invoices — issue, send, chase and record payment

vxcli salesshift invoices checkout <invoice-id>

Create a Stripe payment link for the customer

vxcli salesshift invoices create

Draft an invoice

FlagTypeDefaultWhat it does
--companystringCompany id
--contactstringContact id
--currencystring"USD"Currency
--dealstringDeal id
--duestringDue date (YYYY-MM-DD)
--lines-filestringJSON array of line items
--termsstring"net_14"Payment terms
--titlestringInvoice title

vxcli salesshift invoices from-quote <quote-id>

Turn an accepted quote into an invoice

vxcli salesshift invoices issue <invoice-id>

Issue a draft — assigns the number and freezes the lines

FlagTypeDefaultWhat it does
--duestringDue date (YYYY-MM-DD)

vxcli salesshift invoices list

List invoices

vxcli salesshift invoices pdf <invoice-id>

Download the invoice PDF

FlagTypeDefaultWhat it does
--outstringWhere to write the PDF

vxcli salesshift invoices record-payment <invoice-id>

Record a bank transfer, cheque or cash payment

For money that arrived outside Stripe. It lands in the same ledger with provider "manual", so the invoice's paid/due figures stay correct.

--amount is in CENTS: 250000 is $2,500.00.

FlagTypeDefaultWhat it does
--amountintAmount in CENTS
--methodstring"manual"bank | cheque | cash | manual
--referencestringBank reference

vxcli salesshift invoices send <invoice-id>

Email the invoice with its PDF attached

FlagTypeDefaultWhat it does
--tostringOverride the recipient

vxcli salesshift invoices set-lines <invoice-id>

Replace an invoice's line items from a JSON file

FlagTypeDefaultWhat it does
--lines-filestringJSON array of line items

vxcli salesshift invoices show <invoice-id>

One invoice with its lines and payment state

vxcli salesshift invoices void <invoice-id>

Void an issued invoice

Voiding is not deleting: the number stays used and the record stays auditable, which is the whole point of an invoice sequence.

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift leads

16 commandsdetailed section abovealiases: lead

Prospect pool — search, reveal, save, convert (leads are NOT mailable until converted)

Search the global prospect pool and manage this tenant's saved leads.

A lead is not a contact. Nothing in this command group can email anybody: `leads convert` is the only route from a lead to a mailable Contact.

Addresses are masked ("j•••@acme.com") until revealed, and a reveal spends metered quota — `leads quota` shows the meter.

vxcli salesshift leads bulk-convert <lead-id>…

Convert many saved leads to Contacts

vxcli salesshift leads company <company-id>

Company detail plus its people, split into new prospects and existing contacts

vxcli salesshift leads convert <lead-id>

Saved lead → Contact. This is the ONLY way a record becomes mailable

vxcli salesshift leads convert-from-pool <pool-id>…

Pool → Contact in one step. SPENDS quota unless --no-reveal

Save, reveal if needed, and convert pool rows straight to Contacts.

Revealing spends metered quota, so the cost is printed before anything happens and the result accounts for every id you passed: converted, already converted, and each reason a row was skipped.

--no-reveal spends nothing: only already-revealed rows convert, and the rest come back as skipped_no_quota.

FlagTypeDefaultWhat it does
--no-revealboolSpend nothing: convert only already-revealed rows, report the rest as skipped_no_quota
--yesboolSkip the confirmation — this SPENDS reveals

vxcli salesshift leads enrich <domain|--company-id ID>

Crawl a company's own website and fold what it finds into the pool

Crawl a company's own website and fold what it finds into the pool.

This WRITES to the shared pool, so it plays by the pool's rules:

· Gaps only — an existing description, keyword set or address is never overwritten by a crawl. · Erasure is checked before every insert, so a crawl cannot bring back someone who asked to be forgotten. · Shared mailboxes (sales@, info@, announce@) are not people and are not ingested. · Every address found is recorded as UNVERIFIED. Finding a string on a web page is not verification, and this does not spend reveal quota.

Give a bare domain to crawl a company that is not in the pool yet — the company, and any people found, are created.

FlagTypeDefaultWhat it does
--company-idstringEnrich a company already in the pool, by its pool id

vxcli salesshift leads erasure

Right to be forgotten — GLOBAL across every tenant, and irreversible

Erase a person from the prospect pool.

This is not scoped to your organisation. It deactivates the pool record and strips the address from every saved lead held by EVERY tenant on the platform, and the address is recorded as a hash so future crawls cannot resurrect them.

It cannot be undone.

FlagTypeDefaultWhat it does
--emailstringAddress to erase (required)
--notestringFree-text note for the erasure record
--reasonstring"gdpr_erasure"Reason recorded with the erasure
--yesboolSkip the confirmation — this erases the person for EVERY tenant, irreversibly

vxcli salesshift leads facets

Counts per seniority, department, country and email status for a filter set

FlagTypeDefaultWhat it does
--countrystringArrayISO-2 country, e.g. AU (repeatable)
--departmentstringArrayengineering|sales|marketing|finance|hr|ops|legal|executive (repeatable)
--domainstringArrayCompany domain, e.g. canva.com (repeatable)
--email-statusstringArrayverified|unverified|guessed|catch_all|invalid (repeatable)
--employeesstringArrayCompany size band, e.g. 51-200 (repeatable)
--exclude-titlestringArrayTitle must NOT contain (repeatable)
--has-emailboolOnly rows where an address EXISTS (you still have to reveal it)
--has-phoneboolOnly rows where a phone number exists
--industrystringArrayIndustry, e.g. "Computer Software" (repeatable)
--keywordstringArrayCompany keyword, substring match (repeatable)
--min-scoreintMinimum quality score
--qstringFree text over name, title and company
--senioritystringArrayfounder|c_suite|vp|director|manager|senior|entry (repeatable)
--titlestringArrayTitle contains (repeatable, OR'd)

vxcli salesshift leads get <lead-id>

One saved lead, the live pool row behind it, and any drift between them

vxcli salesshift leads list

This tenant's saved leads (still not mailable — convert first)

FlagTypeDefaultWhat it does
--limitint100Maximum saved leads to return (max 500)
--statusstringFilter by status (new, working, qualified, converted, …)

vxcli salesshift leads quota

Reveals used / allowance / remaining this period

vxcli salesshift leads reveal <pool-id>

Un-mask one pool person — SPENDS one reveal from the metered quota

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation — this SPENDS a reveal

vxcli salesshift leads save <pool-id>…

Copy pool rows into this tenant's saved leads (a snapshot; spends nothing)

vxcli salesshift leads searches [command]

Saved searches

vxcli salesshift leads searches list

List saved searches

vxcli salesshift leads searches save

Save the current filter flags as a named search

FlagTypeDefaultWhat it does
--countrystringArrayISO-2 country, e.g. AU (repeatable)
--departmentstringArrayengineering|sales|marketing|finance|hr|ops|legal|executive (repeatable)
--domainstringArrayCompany domain, e.g. canva.com (repeatable)
--email-statusstringArrayverified|unverified|guessed|catch_all|invalid (repeatable)
--employeesstringArrayCompany size band, e.g. 51-200 (repeatable)
--exclude-titlestringArrayTitle must NOT contain (repeatable)
--has-emailboolOnly rows where an address EXISTS (you still have to reveal it)
--has-phoneboolOnly rows where a phone number exists
--industrystringArrayIndustry, e.g. "Computer Software" (repeatable)
--keywordstringArrayCompany keyword, substring match (repeatable)
--min-scoreintMinimum quality score
--namestringName for the saved search (required)
--qstringFree text over name, title and company
--senioritystringArrayfounder|c_suite|vp|director|manager|senior|entry (repeatable)
--titlestringArrayTitle contains (repeatable, OR'd)

vxcli salesshift leads show <pool-id>

Full detail for one pool person (masking still applies)

vxcli salesshift leads update <lead-id>

Update a saved lead's status or notes

FlagTypeDefaultWhat it does
--notesstringReplace the notes
--statusstringNew status

vxcli salesshift lists

6 commandsaliases: audiences

Contact lists — the audiences campaigns and sequences send to

vxcli salesshift lists add-members <list-id>

Add contacts to a list

FlagTypeDefaultWhat it does
--contactsstringContact ids, comma separated

vxcli salesshift lists create

Create a static list

FlagTypeDefaultWhat it does
--descriptionstringWhat it is for
--namestringList name

vxcli salesshift lists delete <list-id>

Delete a list (the contacts on it are not deleted)

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift lists list

Show every list with its member count

vxcli salesshift lists members <list-id>

Who is on a list

vxcli salesshift lists remove-member <list-id> <contact-id>

Remove one contact from a list

vxcli salesshift opportunities

8 commandsaliases: opps, signals

The shared signal pool — buying and hiring signals

vxcli salesshift opportunities apply <id>

Reply to a signal — records the application AND emails the poster

This is the send half of the opportunity pool.

It writes an application row (so the signal shows your workspace has responded, and a second apply is refused) and then sends a real tracked email to the signal's contact address through the normal sending pipeline. If the signal has no contact email the application is still recorded, and the output says the email was not sent rather than implying it was.

FlagTypeDefaultWhat it does
--messagestringYour pitch (required)
--message-filestringRead the pitch from a file
--ratestringProposed rate, e.g. "$120/hr"

vxcli salesshift opportunities convert <id>

Signal → contact → deal, in one step

push-to-lead stops at the contact. This goes one further and opens a deal in the default pipeline, so a signal you intend to actually pursue lands on the revenue board rather than just in the CRM.

vxcli salesshift opportunities dismiss <id>

Hide a signal from this workspace's feed

vxcli salesshift opportunities list

List signals from the shared pool

FlagTypeDefaultWhat it does
--categorystringFilter by category
--limitint25Rows to return
--min-scoreintMinimum relevance score
--qstringSubstring match on title, company, description or email
--savedboolOnly signals saved by this workspace
--signal-typestringjob_posting | service_request | freelancer_available
--sourcestringhackernews | remoteok | remotive | manual

vxcli salesshift opportunities post

Publish your own signal into the shared pool

The pool is cross-tenant, so anything posted here is visible to every workspace — and the contact address you give is the address applicants will email. Leave --contact-email off and your own account address is used.

FlagTypeDefaultWhat it does
--budget-maxfloatBudget ceiling
--budget-minfloatBudget floor
--categorystringCategory
--companystringCompany name
--contact-emailstringWhere applicants should write
--descriptionstringWhat you need (required)
--locationstringLocation or Remote
--skillsstringComma-separated skills
--titlestringSignal title (required)

vxcli salesshift opportunities push-to-lead <id>

Copy the signal's contact into your CRM

vxcli salesshift opportunities save <id>

Save a signal for this workspace

vxcli salesshift opportunities show <id>

Show one signal in full

vxcli salesshift quotes

10 commandsaliases: quote

Priced proposals — draft, get them approved internally, send

vxcli salesshift quotes approve <quote-id>

Approve a quote internally

vxcli salesshift quotes create

Draft a quote

Line items are too structured for flags, so --lines-file takes a JSON array: [{"name":"Onboarding","quantity":1,"unit_price_cents":250000}]

FlagTypeDefaultWhat it does
--companystringCompany id
--contactstringContact id
--currencystring"USD"Currency
--dealstringDeal id
--lines-filestringJSON array of line items
--titlestringQuote title
--valid-untilstringYYYY-MM-DD

vxcli salesshift quotes decline <quote-id>

Decline internal approval

FlagTypeDefaultWhat it does
--reasonstringWhy approval was declined

vxcli salesshift quotes delete <quote-id>

Delete a quote

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift quotes list

List quotes

vxcli salesshift quotes products

The catalogue quote and invoice lines are built from

vxcli salesshift quotes send <quote-id>

Email the quote to the customer

FlagTypeDefaultWhat it does
--tostringOverride the recipient

vxcli salesshift quotes set-lines <quote-id>

Replace a quote's line items from a JSON file

FlagTypeDefaultWhat it does
--lines-filestringJSON array of line items

vxcli salesshift quotes show <quote-id>

One quote with its line items

vxcli salesshift quotes submit <quote-id>

Submit for internal approval

This is YOUR side's sign-off — a manager approving a discount — not the customer accepting. Acceptance happens on the public quote link.

vxcli salesshift reports

8 commands

Saved and ad-hoc reports over the CRM datasets

vxcli salesshift reports datasets

What can be reported on, and the fields of each

vxcli salesshift reports delete <report-id>

Delete a saved report

vxcli salesshift reports export <report-id>

Download a saved report as CSV

FlagTypeDefaultWhat it does
--formatstring"csv"csv | xlsx
--outstringWhere to write the file

vxcli salesshift reports list

Saved reports

vxcli salesshift reports run

Run an ad-hoc report without saving it

--config-file takes the same JSON the report builder produces: {"columns":["deal.name","deal.amount"],"filters":[],"group_by":null}

FlagTypeDefaultWhat it does
--config-filestringJSON report config
--datasetstringDataset key

vxcli salesshift reports save

Save a report

The server compiles it first — a report that cannot run is never saved.

FlagTypeDefaultWhat it does
--config-filestringJSON report config
--datasetstringDataset key
--namestringReport name

vxcli salesshift reports schedule <report-id>

Email a saved report on a cadence

FlagTypeDefaultWhat it does
--cadencestringdaily | weekly | monthly
--tostringRecipients, comma separated

vxcli salesshift reports schedules <report-id>

Delivery schedules for a saved report

vxcli salesshift seo

12 commands

Site audits, keyword tracking and rank checks

vxcli salesshift seo add-keyword

Track one or more keywords

FlagTypeDefaultWhat it does
--countrystring"us"Country code
--devicestring"desktop"desktop | mobile
--keywordstringKeyword(s), comma separated
--sitestringSite id

vxcli salesshift seo add-site

Track a site

FlagTypeDefaultWhat it does
--domainstringDomain to track
--namestringFriendly name

vxcli salesshift seo audit

Crawl a site and score it

Runs on the tenant node, stores the result and notifies the workspace.

FlagTypeDefaultWhat it does
--max-pagesint20Pages to crawl (1–50)
--sitestringSite id
--urlstringAudit this URL directly

vxcli salesshift seo audit-show <audit-id>

One audit in full

vxcli salesshift seo audits

Past audits

FlagTypeDefaultWhat it does
--sitestringSite id

vxcli salesshift seo check [keyword-id]

Re-check rank — one keyword, or all of them with no argument

vxcli salesshift seo keywords

Tracked keywords and their positions

FlagTypeDefaultWhat it does
--sitestringSite id

vxcli salesshift seo overview

Rollup across every tracked site

vxcli salesshift seo remove-keyword <keyword-id>

Stop tracking a keyword

vxcli salesshift seo remove-site <site-id>

Stop tracking a site

vxcli salesshift seo sites

Tracked sites

vxcli salesshift seo suggest

Keyword ideas from real Google autocomplete

FlagTypeDefaultWhat it does
--countrystring"us"Country code
--seedstringSeed phrase

vxcli salesshift sequences

17 commandsaliases: sequence, seq

Multi-step outbound sequences with delays, A/B variants and stop rules

vxcli salesshift sequences activate <id>

Activate a sequence

vxcli salesshift sequences add-step <sequence-id>

Append an email step

FlagTypeDefaultWhat it does
--bodystringStep HTML body
--body-filestringRead the step body from a file
--delay-daysintDays to wait before this step
--subjectstringStep subject line

vxcli salesshift sequences analytics <id>

Per-step funnel for a sequence

vxcli salesshift sequences archive <id>

Archive a sequence

vxcli salesshift sequences create

Create a sequence, optionally with its first email step

FlagTypeDefaultWhat it does
--bodystringStep HTML body
--body-filestringRead the step body from a file
--delay-daysintDays to wait before this step
--descriptionstringWhat it does
--namestringSequence name
--subjectstringStep subject line

vxcli salesshift sequences dispatch-now

Force the scheduler to run this tenant's due sequence steps now

vxcli salesshift sequences duplicate <id>

Copy a sequence and its steps

vxcli salesshift sequences enroll <id>

Enroll contacts into a sequence

FlagTypeDefaultWhat it does
--contactsstringContact ids, comma separated

vxcli salesshift sequences enrollments <id>

Who is enrolled and where they are in the sequence

vxcli salesshift sequences list

List sequences with their real funnel

FlagTypeDefaultWhat it does
--qstringSearch name and description
--statusstringdraft | active | paused | archived

vxcli salesshift sequences pause <id>

Pause a sequence

vxcli salesshift sequences pause-contact <sequence-id> <enrollment-id>

Pause one contact's enrollment

vxcli salesshift sequences preview <sequence-id>

Render a step exactly as one contact will receive it

Merge tags are resolved against a real contact, so this is the way to catch a "Hi {{first_name}}," that would have gone out with the braces intact. Without --contact a sample contact is used.

FlagTypeDefaultWhat it does
--contactstringRender for this contact
--stepstringStep id to render (required)

vxcli salesshift sequences reorder <sequence-id>

Set the step order

Pass every step id in the order you want, comma separated.

FlagTypeDefaultWhat it does
--stepsstringStep ids in the desired order

vxcli salesshift sequences resume-contact <sequence-id> <enrollment-id>

Resume one contact's enrollment

vxcli salesshift sequences show <id>

One sequence and its step timeline

vxcli salesshift sequences unenroll <sequence-id> <enrollment-id>

Remove someone from a sequence entirely

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift settings

5 commandsaliases: config

Workspace settings — suppressions, team, integrations, mailboxes

vxcli salesshift settings integrations [command]

Sending integrations (BYOK providers)

vxcli salesshift settings integrations delete <integration-id>

Remove an integration and its Vault secrets

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift settings integrations list

Configured integrations

vxcli salesshift settings integrations test <integration-id>

Read the credentials back out of Vault and try them

vxcli salesshift settings mailboxes

Connected sending mailboxes

vxcli salesshift settings poll-replies

Check connected mailboxes for replies right now

vxcli salesshift settings suppressions [command]

The do-not-contact list — a hard gate on every send

vxcli salesshift settings suppressions add

Suppress an address

FlagTypeDefaultWhat it does
--emailstringAddress to suppress
--reasonstring"manual"Why

vxcli salesshift settings suppressions list

Everyone this workspace will never email

vxcli salesshift settings suppressions remove <suppression-id>

Un-suppress an address

Removing a suppression makes that person mailable again. If they unsubscribed themselves, re-adding them is your call to justify, not the platform's — so this asks first.

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift settings team [command]

Workspace members

vxcli salesshift settings team invite

Invite a teammate

FlagTypeDefaultWhat it does
--emailstringWho to invite
--rolestringRole

vxcli salesshift settings team list

Who is on this workspace

vxcli salesshift social

5 commandsaliases: distribute

Social distribution — one post, every network, in parallel

The fan-out runs in the vxsocial Go service: one goroutine per network. Provider calls are simulated unless the deployment holds social API keys — every delivery says which it was.

vxcli salesshift social channels

List distribution channels and their real limits

vxcli salesshift social post

Create a post, and optionally distribute it now

FlagTypeDefaultWhat it does
--channelsstringComma-separated channel keys
--concurrencyintMax parallel channels (0 = all at once)
--contentstringPost body (required)
--distributeboolDistribute immediately after creating
--hashtagsstringComma-separated hashtags
--imagesintNumber of attached images
--linkstringURL to include
--schedulestringRFC3339 time — queues it for the Celery worker
--titlestringInternal title

vxcli salesshift social posts

List posts and their delivery outcomes

vxcli salesshift social send <post-id>

Distribute (or re-distribute) an existing post

FlagTypeDefaultWhat it does
--concurrencyintMax parallel channels (0 = all at once)

vxcli salesshift social stats

Distribution totals for this workspace

vxcli salesshift stats

1 commandsdetailed section above

SalesShift dashboard stats (contacts, deals, email funnel)

vxcli salesshift stats

SalesShift dashboard stats (contacts, deals, email funnel)

vxcli salesshift subscriptions

6 commandsaliases: subs, recurring

Your customers' recurring revenue (NOT your own SalesShift plan)

vxcli salesshift subscriptions cancel <subscription-id>

Cancel a subscription

FlagTypeDefaultWhat it does
--at-period-endbooltrueKeep it running until the period closes (false stops it today)
--reasonstringChurn reason
--yesboolSkip the confirmation prompt

vxcli salesshift subscriptions create

Start a subscription

--items-file takes a JSON array: [{"product_id":"…","quantity":2,"unit_price_cents":5000}]

FlagTypeDefaultWhat it does
--companystringCompany id
--contactstringContact id
--currencystring"USD"Currency
--intervalstring"month"month | year
--items-filestringJSON array of items

vxcli salesshift subscriptions list

Active and cancelled subscriptions

vxcli salesshift subscriptions mrr

Recurring revenue summary

vxcli salesshift subscriptions reactivate <subscription-id>

Undo a pending cancellation

vxcli salesshift subscriptions show <subscription-id>

One subscription and its items

vxcli salesshift tasks

5 commands

Tasks — description, due date, owner and target goal

vxcli salesshift tasks add

Create a task

FlagTypeDefaultWhat it does
--descriptionstringWhat to do
--duestringDue date (RFC3339 or YYYY-MM-DD)
--goalstringTarget goal / delivery — what does done look like?
--prioritystring"medium"low | medium | high
--progressint0–100
--titlestringTask title (required)
--typestring"todo"todo | call | email | meeting

vxcli salesshift tasks delete <task-id>

Delete a task

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift tasks done <task-id>

Mark a task complete (progress goes to 100)

vxcli salesshift tasks list

List tasks

FlagTypeDefaultWhat it does
--prioritystringlow | medium | high
--statusstringopen | done | cancelled
--typestringtodo | call | email | meeting

vxcli salesshift tasks update <task-id>

Edit a task — title, description, goal, due date, priority or progress

Only the flags you pass are sent, so moving a due date cannot silently blank out the goal the way a full replace would.

FlagTypeDefaultWhat it does
--descriptionstringNew description
--duestringNew due date (RFC3339 or YYYY-MM-DD)
--goalstringNew target goal / delivery
--prioritystringlow | medium | high
--progressint0–100
--statusstringopen | done | cancelled
--titlestringNew title
--typestringtodo | call | email | meeting

vxcli salesshift webmaster

4 commandsaliases: seo

Inspect a live URL, robots.txt and sitemap.xml

vxcli salesshift webmaster generate <domain>

Generate robots.txt and sitemap.xml

FlagTypeDefaultWhat it does
--disallowstring"/api/,/admin/"Comma-separated Disallow rules
--pathsstring"/"Comma-separated paths for the sitemap

vxcli salesshift webmaster inspect <url>

Report what a crawler finds on a page

vxcli salesshift webmaster robots <url>

Read and summarise a site's robots.txt

vxcli salesshift webmaster sitemap <url>

Fetch and summarise a sitemap

vxcli salesshift worker

1 commandsdetailed section above

Tenant email-worker operations

vxcli salesshift worker health

Health of the tenant node email worker

vxcli salesshift workflows

11 commandsaliases: workflow, automations

Automation workflows — the /automations canvas, from a terminal

vxcli salesshift workflows activate <id>

Activate a workflow

vxcli salesshift workflows create

Create an empty workflow (build the graph on the canvas or with update)

FlagTypeDefaultWhat it does
--descriptionstringWhat it does
--namestringWorkflow name
--triggerstringTrigger type

vxcli salesshift workflows delete <id>

Delete a workflow and its run history

FlagTypeDefaultWhat it does
--yesboolSkip the confirmation prompt

vxcli salesshift workflows duplicate <id>

Copy a workflow

vxcli salesshift workflows enroll <id>

Enroll contacts — one run each (workflow must be active)

FlagTypeDefaultWhat it does
--contactsstringContact ids, comma separated

vxcli salesshift workflows list

List workflows

FlagTypeDefaultWhat it does
--statusstringdraft | active | paused

vxcli salesshift workflows pause <id>

Pause a workflow

vxcli salesshift workflows runs <id>

Recent runs for a workflow

vxcli salesshift workflows show <id>

One workflow with its graph

vxcli salesshift workflows test-run <id>

Execute the graph once and print the step-by-step trace

Side effects are simulated. Pass --live to actually send. With no --contact a transient sample contact is used and the run is flagged as a sample, so nothing pollutes your real run history.

FlagTypeDefaultWhat it does
--contactstringRun against this contact instead of a sample
--liveboolReally perform side effects

vxcli salesshift workflows validate <id>

Check the graph without running it

What was and was not run

The groups documented in prose above were executed against a live system and their output pasted verbatim. On 2026-08-12 a second pass ran the CRM, automation and signal groups against https://api.vxcloud.io: tasks create/update/complete/delete, workflow validate, test-run and enroll, a sequence taken from create through step, activate, enroll, analytics and pause, and an opportunity applied to — which recorded the application and delivered a real email, with a second apply correctly refused 409.

That pass found nine defects, three of which were the dangerous kind that returns a plausible number rather than an error: a multi-word --q was not percent-encoded and answered 400; contact search matched column by column, so "Joel" and "Wembo" each found people but "Joel Wembo" found none; and sequence analytics read its counters one level above where they live, reporting 0 sent for a sequence that had really sent eight. All nine are fixed and re-verified.

On 2026-08-13 the free-tier additions to billing were run against http://localhost:8741: entitlements in both renderings, node, and two of the three node register refusals. The commands that change what a workspace is paying, or stop it sending, were not.

The exceptions below were never run, for the reasons given.

CommandStatusWhy
leads erasurenot runGlobal and irreversible across every tenant, against a real person. Only its --email guard was exercised. Everything else about it on this page is read from the source and labelled as such.
billing activatenot runThe workspace these captures come from is a comped Organization. Activating a free plan would have taken that away, and the command’s own refusal rules mean it could not simply be undone.
billing node detachnot runThere was no node registered to detach, and detaching a real one stops that tenant sending until another is registered.
billing node register <host>refusals onlyAll three refusal paths — 403, 400 and 502 — were run live, and none of them wrote anything. A successful registration was not: it needs a node whose /health answers with thisworkspace’s tenant id, and repointing a live sending workspace at one is not a thing to do for a screenshot.

Three commands were run in a mode that deliberately avoids a side effect, and the page says which mode: convert-from-pool with --no-reveal (spent nothing, created nothing), bulk-convert against one already-converted and one unrevealed lead (converted nothing new), and enrich against a company already in the pool (added nothing). One reveal and one conversion were genuinely spent, and one real email was sent, so that those three could be shown working rather than described.