Reference
vxcli salesshift
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.
curl -fsSL https://vxcloud.io/download/cli/install.sh | shirm https://vxcloud.io/download/cli/install.ps1 | iexBoth 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.
cd vxnode/services/cli
go build -buildvcs=false -o vxcli . # Go 1.21+; -buildvcs=false is required
./vxcli salesshift --helpBuilding 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.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 outputThe 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.
# 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 --deviceHow a credential is chosen
One rule, applied per request in ssAuthHeaders: a JWT beats an API key, and nothing else is consulted.
| Order | Condition | Header sent |
|---|---|---|
| 1 | access_token is non-empty in the config | Authorization: Bearer <jwt> |
| 2 | otherwise api_key is non-empty | X-API-Key: xc_… |
| 3 | neither is set, or the file cannot be read | nothing is sent; the command exits 1 before any request goes out |
The CLI does not refresh a JWT for you
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
~/.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.
| Base | Resolution order | Used by |
|---|---|---|
| VxCloud | VXCLOUD_URL → base_url from the config (only if it looks public) → https://api.vxcloud.io | Every command except worker health |
| Node | VX_NODE_URL → NODE_URL → node_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
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
| Flag | Default | Effect |
|---|---|---|
| --output | text | text, 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.json | Alternate credentials file. |
| --no-color | false | Drops ANSI colour. Every capture on this page was taken with it. |
| --debug / --verbose / --quiet | false | Root-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.
vxcli --no-color --output json salesshift leads quota{
"allowance": 2500000,
"display": "27 / 2500000",
"remaining": 2499973,
"unlimited": false,
"used": 27
}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
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 liveThe SalesShift dashboard aggregate: CRM counts and the email funnel.
- Calls
- GET {vxcloud}/api/v1/salesshift/stats
No flags.
vxcli --no-color salesshift stats ▎ SalesShift stats ────────────────────────────────────────────
Contacts 37
Companies 1
Open deals 22
Active sequences 1
Emails sent 205
Emails opened 21
Emails replied 4The 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.
vxcli salesshift email send
Called liveSend 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --torequired | string | "" | Recipient address. |
| --subjectrequired | string | "" | Subject. Merge tags such as {{first_name}} resolve against the contact record. |
| --body | string | "" | HTML body. Required unless --body-file is given. |
| --body-file | string | "" | Read the HTML body from a file. A read error exits 1 before anything is sent. |
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>" ▎ Email sent ──────────────────────────────────────────────────
To [email protected]
Provider smtp
Tracking ID ea81efd0d7dc4a8388868e1e387c56d2This sends a real message
successis true; on failure it prints the server’s detail, or its error when there is no detail.vxcli salesshift email list
Called liveThe org's outbound feed with its engagement state.
- Calls
- GET {vxcloud}/api/v1/salesshift/emails[?status=]
| Flag | Type | Default | What it does |
|---|---|---|---|
| --status | string | "" | Filter by status — sent, opened, clicked, replied, bounced, unsubscribed, failed. Empty returns everything. |
vxcli --no-color salesshift email list --status sent ▎ 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%-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 liveHealth 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.
vxcli --no-color salesshift worker health ▎ Email worker ────────────────────────────────────────────────
Node http://127.0.0.1:8744
Status healthy
Providers [smtp]
Redis true
Domain rate/min 20Node 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 convertand 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_emailsays an address exists;email_revealedsays you may see it. - Reveal spends metered quota. Every spending path prints the cost before acting and needs
--yes, or an interactivey/N. A pipe or a CI job that cannot answer counts as no.
vxcli salesshift leads search
Called liveSearch the global pool — people by default, companies with --companies.
- Calls
- POST {vxcloud}/api/v1/salesshift/leads/search
| Flag | Type | Default | What it does |
|---|---|---|---|
| --q | string | "" | Free text over name, title and company. |
| --titlerepeatable | string | — | Title contains. Repeat to OR several. |
| --exclude-titlerepeatable | string | — | Title must NOT contain. Repeat to exclude several. |
| --seniorityrepeatable | string | — | One of founder c_suite vp director manager senior entry. |
| --departmentrepeatable | string | — | One of engineering sales marketing finance hr ops legal executive. |
| --countryrepeatable | string | — | ISO-2 country code, e.g. AU. Upper-cased server-side. |
| --industryrepeatable | string | — | Industry, e.g. "Computer Software". |
| --email-statusrepeatable | string | — | verified unverified guessed catch_all invalid. |
| --employeesrepeatable | string | — | Company size band, e.g. 51-200, 5000+. |
| --domainrepeatable | string | — | Company domain, e.g. northwind.example. |
| --keywordrepeatable | string | — | Company keyword, substring match — "saas" also matches "saas management". |
| --min-score | int | 0 | Minimum quality score. 0 means no constraint. |
| --has-email | bool | unset | Only 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-phone | bool | unset | Only rows where a phone number exists. Tri-state, same as above. |
| --sort | string | score | People: score name title company location employees email. Companies: score name employees industry location. An unknown field degrades to score desc server-side and the command says so. |
| --desc | bool | per column | Descending. Left off, numeric columns default descending and text columns ascending. |
| --limit | int | 25 | Rows per page. Clamped client-side to 1–100. Under --all the default becomes 100. |
| --cursor | string | "" | Opaque cursor from a previous page. Never edit one; never reuse one after changing --sort or a filter. |
| --all | bool | false | Walk every page. Stops after 200 pages and says the set is incomplete rather than implying it finished. |
| --companies | bool | false | Return companies instead of people. |
vxcli --no-color salesshift leads search --country AU --limit 5 ▎ Pool — people (5 shown) ───────────────────────────────────
Matches 65
Sort (applied) score desc
Backend go-node
NAME TITLE COMPANY LOCATION SCORE
Sofia Ferreira Founder Kestrel Data Melbourne, AU 62
7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 s•••@kestreldata.example (masked — not revealed) · unverified · phone×1
Mia Calderon Founder Fjord Energy Melbourne, AU 61
2c5f83b1-4ad7-5920-b16e-8f3d07ca4b12 m•••@fjord.example (masked — not revealed) · unverified · phone×2
Riley Ashworth Head of Growth Cobalt Retail Sydney, AU 61
9e0b76d3-2f18-5c44-8ad2-5b91e6f03847 r•••@cobalt.example (masked — not revealed) · unverified · phone×1
Mateo Bianchi Sales Manager Terra Logistica Perth, AU 61
4f81c206-6e33-59ab-9c07-3d2a85be1f60 m•••@terra.example (masked — not revealed) · unverified
Callum Reyes Founder Helix Mfg Adelaide, AU 61
6a3d9f57-8b40-5d61-ae92-7c14f80b25d3 c•••@helix.example (masked — not revealed) · unverified
(masked) is not a real address — `vxcli salesshift leads reveal <pool-id>` spends one reveal.
Next page: rerun with --cursor NjE.6a3d9f57-8b40-5d61-ae92-7c14f80b25d3
The cursor is opaque and valid only for these exact filters and this sort.The id under each row is the pool id. It is what reveal, save, show and convert-from-pool take — not the lead id that leads list prints.
Sort (applied) is the sort the server used. Ask for a column that does not exist and it degrades silently server-side, so the command compares the two and warns:
▎ Pool — people (2 shown) ───────────────────────────────────
Matches 260
Sort (applied) score desc
! "nonsense" is not a sortable field here — the server used score desc
Backend go-node--companies switches the result type and the columns:
▎ Pool — companies (4 shown) ────────────────────────────────
Matches 12
Sort (applied) score desc
Backend go-node
NAME INDUSTRY LOCATION EMPLOYEES SCORE
Northwind Systems Computer Software Sydney, AU 400 85
5b71e824-3c9d-4a16-92f0-6e83d1057ac4 northwind.example
Fjord Energy Computer Software Brisbane, AU 200 84
8f24a0b6-1d75-4e38-b6c1-42a97f0e35d8 fjord.example
Kestrel Data Computer Software Melbourne, AU 1500 81
c93e17d5-6b28-4f90-a715-08c3b64de921 kestreldata.example
Terra Logistica Computer Software Sydney, AU 1000 78
1a6c8f30-49b7-4d25-8e63-b5f072a19c4e terra.example
Next page: rerun with --cursor Nzg.1a6c8f30-49b7-4d25-8e63-b5f072a19c4eCompany results paged here, contrary to the source comments
next_cursor. Against the go-node backend on this system it did not: a company search with --limit 2 returned next_cursor: "ODQ.40f11596-…". Trust the field you are handed rather than the comment.--all pages to exhaustion, reports how many pages it walked, and never pretends a truncated walk was a complete one:
▎ Pool — people (11 shown) ──────────────────────────────────
Matches 11
Sort (applied) score desc
Backend go-node
Pages walked 1
NAME TITLE COMPANY LOCATION SCORE
Sofia Ferreira Founder Kestrel Data Melbourne, AU 62
7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 [email protected] · unverified · phone×1 · saved
Mia Calderon Founder Fjord Energy Melbourne, AU 61
2c5f83b1-4ad7-5920-b16e-8f3d07ca4b12 m•••@fjord.example (masked — not revealed) · unverified · phone×2 · savedvxcli salesshift leads facets
Called liveCounts 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --q | string | "" | Free text over name, title and company. |
| --titlerepeatable | string | — | Title contains. Repeat to OR several. |
| --exclude-titlerepeatable | string | — | Title must NOT contain. Repeat to exclude several. |
| --seniorityrepeatable | string | — | One of founder c_suite vp director manager senior entry. |
| --departmentrepeatable | string | — | One of engineering sales marketing finance hr ops legal executive. |
| --countryrepeatable | string | — | ISO-2 country code, e.g. AU. Upper-cased server-side. |
| --industryrepeatable | string | — | Industry, e.g. "Computer Software". |
| --email-statusrepeatable | string | — | verified unverified guessed catch_all invalid. |
| --employeesrepeatable | string | — | Company size band, e.g. 51-200, 5000+. |
| --domainrepeatable | string | — | Company domain, e.g. northwind.example. |
| --keywordrepeatable | string | — | Company keyword, substring match — "saas" also matches "saas management". |
| --min-score | int | 0 | Minimum quality score. 0 means no constraint. |
| --has-email | bool | unset | Only 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-phone | bool | unset | Only rows where a phone number exists. Tri-state, same as above. |
vxcli --no-color salesshift leads facets --country AU ▎ 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 4Facets 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 liveThe reveal meter for the current period.
- Calls
- GET {vxcloud}/api/v1/salesshift/leads/quota
No flags.
vxcli --no-color salesshift leads quota ▎ Reveal quota ────────────────────────────────────────────────
Used 2 / 200
Allowance 200
Remaining 198Remaining 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 liveUn-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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | false | Skip the confirmation. This spends a reveal. |
vxcli --no-color salesshift leads reveal 7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 --yes ! 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.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 liveCopy 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.
vxcli --no-color salesshift leads save \
7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 \
1978d19c-2fba-515b-85cc-9fb48034e9f7 ▎ 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.vxcli salesshift leads show <pool-id>
Called liveFull 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.
vxcli --no-color salesshift leads show 7d2e1a44-90bc-5e17-a3f6-1b8c40d92e55 ▎ 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.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 liveCompany 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 --companiesand byleads show.
No flags.
vxcli --no-color salesshift leads company 5b71e824-3c9d-4a16-92f0-6e83d1057ac4 ▎ 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.vxcli salesshift leads list
Called liveThis tenant's saved leads. Still not mailable — convert first.
- Calls
- GET {vxcloud}/api/v1/salesshift/leads?limit=&status=
| Flag | Type | Default | What it does |
|---|---|---|---|
| --status | string | "" | new, contacted, working, qualified, converted, disqualified. |
| --limit | int | 100 | Clamped 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. |
vxcli --no-color salesshift leads list --limit 5 ▎ 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.Two different id spaces
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 liveOne 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>fromleads list.
No flags.
vxcli --no-color salesshift leads get 6b2f8a14-77c3-4de9-b105-3ea9c5148d77 ▎ 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 —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 liveUpdate 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>.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --status | string | "" | New status. Only sent if the flag was given. |
| --notes | string | "" | Replaces the notes. Pass an empty string to clear them. |
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." ▎ 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.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 liveSaved 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.
vxcli --no-color salesshift leads convert 3e91c7a5-0b64-4f28-9d13-7a205ce8b641 ▎ 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.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 liveConvert 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.
vxcli --no-color salesshift leads bulk-convert \
3e91c7a5-0b64-4f28-9d13-7a205ce8b641 \
0b7f7b09-2fab-46da-99dd-4895ebb99d72 ▎ 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.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 liveSave, 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --no-reveal | bool | false | Spend nothing: convert only rows already revealed, and report the rest as skipped_no_quota. |
| --yes | bool | false | Skip the confirmation. This spends reveals unless --no-reveal is also set. |
vxcli --no-color salesshift leads convert-from-pool \
8a28e51d-8811-5fc2-9819-c6d75cbb1310 \
be6215a3-54cd-58fe-a36e-a41fcb5a95f6 \
--no-reveal --yes ! 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 197Every 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 liveCrawl 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company-id | string | "" | Enrich a company already in the pool, by its pool id, instead of passing a domain. |
vxcli --no-color salesshift leads enrich example.com 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.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
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 hereRight to be forgotten. Global across every tenant on the platform, and irreversible.
- Calls
- POST {vxcloud}/api/v1/salesshift/leads/erasure
| Flag | Type | Default | What it does |
|---|---|---|---|
| --emailrequired | string | "" | The address to erase. Missing or blank exits 1 before any request. |
| --reason | string | gdpr_erasure | Reason recorded with the erasure. |
| --note | string | "" | Free-text note for the erasure record. |
| --yes | bool | false | Skip the confirmation. This erases the person for every tenant, irreversibly. |
Not executed while writing this page
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.
! 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 liveThis org's saved searches.
- Calls
- GET {vxcloud}/api/v1/salesshift/lead-searches
No flags.
vxcli --no-color salesshift leads searches list ▎ Saved searches (1) ──────────────────────────────────────────
AU founders with an address e8176c8a-7798-4971-ba47-7871763967a5vxcli salesshift leads searches save
Called liveStore 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --namerequired | string | "" | Name for the saved search. Missing or blank exits 1. |
| --q | string | "" | Free text over name, title and company. |
| --titlerepeatable | string | — | Title contains. Repeat to OR several. |
| --exclude-titlerepeatable | string | — | Title must NOT contain. Repeat to exclude several. |
| --seniorityrepeatable | string | — | One of founder c_suite vp director manager senior entry. |
| --departmentrepeatable | string | — | One of engineering sales marketing finance hr ops legal executive. |
| --countryrepeatable | string | — | ISO-2 country code, e.g. AU. Upper-cased server-side. |
| --industryrepeatable | string | — | Industry, e.g. "Computer Software". |
| --email-statusrepeatable | string | — | verified unverified guessed catch_all invalid. |
| --employeesrepeatable | string | — | Company size band, e.g. 51-200, 5000+. |
| --domainrepeatable | string | — | Company domain, e.g. northwind.example. |
| --keywordrepeatable | string | — | Company keyword, substring match — "saas" also matches "saas management". |
| --min-score | int | 0 | Minimum quality score. 0 means no constraint. |
| --has-email | bool | unset | Only 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-phone | bool | unset | Only rows where a phone number exists. Tri-state, same as above. |
vxcli --no-color salesshift leads searches save \
--name "AU founders with an address" \
--country AU --seniority founder --has-email ▎ Search saved ────────────────────────────────────────────────
ID e8176c8a-7798-4971-ba47-7871763967a5
Name AU founders with an addressThere 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 liveThe 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
entandallowance.
No flags.
vxcli --no-color salesshift billing entitlements 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 unlimitedWho 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
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.
{
"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"
}vxcli salesshift billing node
Called liveThe 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--helpshows two usage lines.
No flags.
vxcli --no-color salesshift billing node 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 /healthThe 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 liveRegister 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 forlocalhostand127.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.
$ 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 1Running 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.
| Status | Headline | What it means |
|---|---|---|
| 400 | Refused — 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. |
| 403 | Not 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. |
| 502 | The node did not answer. | The probe failed outright — DNS, TLS or a firewall. Run live, above. |
How the 403 was reached
/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 hereForget 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
unregisterandremove.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | false | Skip 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 hereMove this workspace onto a free plan. No card, no Stripe, no $0 price object.
- Calls
- POST {vxcloud}/api/v1/salesshift/billing/activate
| Flag | Type | Default | What it does |
|---|---|---|---|
| --plan | string | "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.
| Status | What the CLI prints | What 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:
$ 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 1The 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
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.| Group | Commands | What it covers |
|---|---|---|
| analytics | 10 | The numbers behind the dashboards |
| billing | 12 | Your SalesShift plan — pricing, seats, invoices |
| calendar | 10 | Meetings — agenda, events and invitations |
| campaigns | 11 | Email campaigns and their reports |
| companies | 4 | Accounts — the companies behind your contacts |
| contacts | 13 | Your CRM contacts — the only records that are mailable |
| contracts | 7 | Contracts — draft, send for signature, track and audit |
| conversations | 2 | Reply threads — what came back from your sends |
| deals | 8 | Pipelines and deals — the revenue board |
| deliverability | 13 | Inbox health, domain auth and placement — why mail lands or does not |
| 2 | SalesShift email operations | |
| goals | 3 | Quota targets and the leaderboard |
| invoices | 11 | Invoices — issue, send, chase and record payment |
| leads | 16 | Prospect pool — search, reveal, save, convert (leads are NOT mailable until converted) |
| lists | 6 | Contact lists — the audiences campaigns and sequences send to |
| opportunities | 8 | The shared signal pool — buying and hiring signals |
| quotes | 10 | Priced proposals — draft, get them approved internally, send |
| reports | 8 | Saved and ad-hoc reports over the CRM datasets |
| seo | 12 | Site audits, keyword tracking and rank checks |
| sequences | 17 | Multi-step outbound sequences with delays, A/B variants and stop rules |
| settings | 5 | Workspace settings — suppressions, team, integrations, mailboxes |
| social | 5 | Social distribution — one post, every network, in parallel |
| stats | 1 | SalesShift dashboard stats (contacts, deals, email funnel) |
| subscriptions | 6 | Your customers' recurring revenue (NOT your own SalesShift plan) |
| tasks | 5 | Tasks — description, due date, owner and target goal |
| webmaster | 4 | Inspect a live URL, robots.txt and sitemap.xml |
| worker | 1 | Tenant email-worker operations |
| workflows | 11 | Automation workflows — the /automations canvas, from a terminal |
vxcli salesshift analytics
10 commandsaliases:stats-detailThe numbers behind the dashboards
vxcli salesshift analytics activity
Activity timeline
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics campaigns
Campaign performance
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics contract-cycle
Contract cycle
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics email
Email analytics
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics engagement
Engagement
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics funnel
Conversion funnel
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics health
Activity health
vxcli salesshift analytics overview
Overview
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics sales
Sales analytics
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
vxcli salesshift analytics timeseries
Time series
| Flag | Type | Default | What it does |
|---|---|---|---|
| --days | int | 30 | Window in days (1–365) |
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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --plan | string | "self_hosted" | Free plan code to activate (only plans flagged free are accepted) |
vxcli salesshift billing cancel
Cancel the subscription
| Flag | Type | Default | What it does |
|---|---|---|---|
| --at-period-end | bool | true | Keep access until the period closes (false cancels immediately) |
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift billing change
Change plan and/or seat count
| Flag | Type | Default | What it does |
|---|---|---|---|
| --plan | string | — | New plan code |
| --seats | int | — | New 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --plan | string | — | starter | professional | organization |
| --seats | int | 1 | Number 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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:calMeetings — 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contact | string | — | Contact id |
| --end | string | — | End (RFC3339) |
| --guests | string | — | Guest emails, comma separated |
| --location | string | — | Where |
| --no-invites | bool | — | Record guests without mailing them |
| --start | string | — | Start (RFC3339) |
| --title | string | — | Meeting title |
| --url | string | — | Meeting link |
vxcli salesshift calendar delete <event-id>
Cancel an event
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift calendar duplicate <event-id>
Copy an event
vxcli salesshift calendar events
Events in a window
| Flag | Type | Default | What it does |
|---|---|---|---|
| --from | string | — | Window start (RFC3339) |
| --to | string | — | Window end (RFC3339) |
vxcli salesshift calendar export
Download the calendar as an .ics file
| Flag | Type | Default | What it does |
|---|---|---|---|
| --out | string | — | Where to write the .ics |
vxcli salesshift calendar invite <event-id>
Invite more guests to an existing event
| Flag | Type | Default | What it does |
|---|---|---|---|
| --guests | string | — | Guest 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:campaignEmail 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contacts | string | — | Contact ids |
| --lists | string | — | List 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --body | string | — | HTML body |
| --body-file | string | — | Read the HTML body from a file |
| --contacts | string | — | Comma-separated contact ids |
| --from-email | string | — | From address (default: the org's default integration) |
| --from-name | string | — | From display name |
| --lists | string | — | Comma-separated list ids |
| --name | string | — | Campaign name (required) |
| --reply-to | string | — | Reply-To address |
| --send | bool | — | Send immediately after creating |
| --subject | string | — | Subject line — merge tags allowed |
vxcli salesshift campaigns delete <campaign-id>
Delete a campaign and its recipient rows
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --to | string | — | Override 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, accountsAccounts — the companies behind your contacts
vxcli salesshift companies create
Create a company
| Flag | Type | Default | What it does |
|---|---|---|---|
| --domain | string | — | Primary domain |
| --employees | int | — | Employee count |
| --industry | string | — | Industry |
| --name | string | — | Company name |
vxcli salesshift companies delete <company-id>
Delete a company
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift companies list
List companies
| Flag | Type | Default | What it does |
|---|---|---|---|
| --limit | int | 25 | Rows to return |
| --q | string | — | Search name or domain |
vxcli salesshift companies update <company-id>
Update a company
| Flag | Type | Default | What it does |
|---|---|---|---|
| --domain | string | — | Primary domain |
| --employees | int | — | Employee count |
| --industry | string | — | Industry |
| --name | string | — | Company name |
vxcli salesshift contacts
13 commandsaliases:contactYour 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company | string | — | Company name |
| string | — | Email address | |
| --first | string | — | First name |
| --last | string | — | Last name |
| --phone | string | — | Phone number |
| --title | string | — | Job title |
vxcli salesshift contacts delete <id>
Delete a contact
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --body | string | — | HTML body |
| --body-file | string | — | Read the HTML body from a file |
| --from-email | string | — | Override the From address |
| --reply-to | string | — | Override Reply-To |
| --subject | string | — | Subject line |
vxcli salesshift contacts enrich
Fill in missing company, title and social data
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contacts | string | — | Contact 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --file | string | — | JSON array of contacts |
vxcli salesshift contacts list
List contacts
| Flag | Type | Default | What it does |
|---|---|---|---|
| --has-email | bool | — | Only contacts with an address |
| --limit | int | 25 | Rows to return (max 100) |
| --min-score | int | — | Minimum total score |
| --q | string | — | Search name, email, company or title |
| --stage | string | — | Lifecycle 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --text | string | — | Note 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company | string | — | Company name |
| string | — | Email address | |
| --first | string | — | First name |
| --last | string | — | Last name |
| --phone | string | — | Phone number |
| --stage | string | — | Lifecycle stage |
| --title | string | — | Job title |
vxcli salesshift contracts
7 commandsaliases:contractContracts — 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --body-file | string | — | HTML body file |
| --deal | string | — | Deal id |
| --party-a | string | — | Your side's name |
| --party-a-email | string | — | Your side's email |
| --party-b | string | — | Counterparty name |
| --party-b-email | string | — | Counterparty email |
| --title | string | — | Contract title |
vxcli salesshift contracts delete <contract-id>
Delete a contract
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --out | string | — | Where 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --deal | string | — | Deal id |
| --file | string | — | PDF to upload |
| --party-a | string | — | Your side's name |
| --party-a-email | string | — | Your side's email |
| --party-b | string | — | Counterparty name |
| --party-b-email | string | — | Counterparty email |
| --title | string | — | Contract title |
vxcli salesshift conversations
2 commandsaliases:inbox, threadsReply 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, pipelinePipelines and deals — the revenue board
vxcli salesshift deals create
Create a deal (defaults to the first stage of the default pipeline)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --amount | float | — | Deal value |
| --close | string | — | Expected close date (YYYY-MM-DD) |
| --company | string | — | Company id |
| --contact | string | — | Contact id |
| --currency | string | "USD" | Currency code |
| --name | string | — | Deal name |
| --pipeline | string | — | Pipeline id |
| --stage | string | — | Stage id |
| --tags | string | — | Comma-separated tags |
vxcli salesshift deals delete <deal-id>
Delete a deal
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --category | string | — | commit | best_case | pipeline | omitted |
vxcli salesshift deals list
List deals
| Flag | Type | Default | What it does |
|---|---|---|---|
| --pipeline | string | — | Pipeline id |
| --status | string | — | open | 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --stage | string | — | Target stage id (required) |
vxcli salesshift deals pipelines
Pipelines and their stages
vxcli salesshift deals update <deal-id>
Update a deal
| Flag | Type | Default | What it does |
|---|---|---|---|
| --amount | float | — | Deal value |
| --close | string | — | Expected close date (YYYY-MM-DD) |
| --company | string | — | Company id |
| --contact | string | — | Contact id |
| --currency | string | "USD" | Currency code |
| --lost-reason | string | — | Why it was lost |
| --name | string | — | Deal name |
| --status | string | — | open | won | lost |
vxcli salesshift deliverability
13 commandsaliases:delivInbox health, domain auth and placement — why mail lands or does not
vxcli salesshift deliverability alerts
Open deliverability alerts
| Flag | Type | Default | What it does |
|---|---|---|---|
| --history | bool | — | Show 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)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --daily-cap | int | — | Max sends per day |
| --in-pool | bool | true | Include in the sending pool |
| --send-gap | int | — | Seconds 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --inbox | string | — | Probe from this inbox |
vxcli salesshift deliverability seed-add
Add a seed inbox
| Flag | Type | Default | What it does |
|---|---|---|---|
| string | — | Seed 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
SalesShift email operations
vxcli salesshift email list
List tracked emails and their engagement state
| Flag | Type | Default | What it does |
|---|---|---|---|
| --status | string | — | Filter by status (sent, opened, replied, bounced, …) |
vxcli salesshift email send
Send a tracked email (suppression gate, caps, tenant node worker)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --body | string | — | HTML body |
| --body-file | string | — | Read HTML body from a file |
| --subject | string | — | Email subject (merge tags like {{first_name}} allowed) |
| --to | string | — | Recipient email address |
vxcli salesshift goals
3 commandsQuota targets and the leaderboard
vxcli salesshift goals create
Set a goal
| Flag | Type | Default | What it does |
|---|---|---|---|
| --end | string | — | Period end (YYYY-MM-DD) |
| --metric | string | — | Metric key |
| --owner | string | — | Whose goal (default: you) |
| --period | string | "month" | month | quarter | year |
| --start | string | — | Period start (YYYY-MM-DD) |
| --target | int | — | Target value |
vxcli salesshift goals leaderboard
Who is ahead
| Flag | Type | Default | What it does |
|---|---|---|---|
| --end | string | — | Period end (YYYY-MM-DD) |
| --start | string | — | Period start (YYYY-MM-DD) |
vxcli salesshift goals list
Goals and progress against them
vxcli salesshift invoices
11 commandsaliases:invoiceInvoices — 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company | string | — | Company id |
| --contact | string | — | Contact id |
| --currency | string | "USD" | Currency |
| --deal | string | — | Deal id |
| --due | string | — | Due date (YYYY-MM-DD) |
| --lines-file | string | — | JSON array of line items |
| --terms | string | "net_14" | Payment terms |
| --title | string | — | Invoice 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --due | string | — | Due date (YYYY-MM-DD) |
vxcli salesshift invoices list
List invoices
vxcli salesshift invoices pdf <invoice-id>
Download the invoice PDF
| Flag | Type | Default | What it does |
|---|---|---|---|
| --out | string | — | Where 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --amount | int | — | Amount in CENTS |
| --method | string | "manual" | bank | cheque | cash | manual |
| --reference | string | — | Bank reference |
vxcli salesshift invoices send <invoice-id>
Email the invoice with its PDF attached
| Flag | Type | Default | What it does |
|---|---|---|---|
| --to | string | — | Override the recipient |
vxcli salesshift invoices set-lines <invoice-id>
Replace an invoice's line items from a JSON file
| Flag | Type | Default | What it does |
|---|---|---|---|
| --lines-file | string | — | JSON 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip the confirmation prompt |
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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --no-reveal | bool | — | Spend nothing: convert only already-revealed rows, report the rest as skipped_no_quota |
| --yes | bool | — | Skip 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company-id | string | — | Enrich 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| string | — | Address to erase (required) | |
| --note | string | — | Free-text note for the erasure record |
| --reason | string | "gdpr_erasure" | Reason recorded with the erasure |
| --yes | bool | — | Skip 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --country | stringArray | — | ISO-2 country, e.g. AU (repeatable) |
| --department | stringArray | — | engineering|sales|marketing|finance|hr|ops|legal|executive (repeatable) |
| --domain | stringArray | — | Company domain, e.g. canva.com (repeatable) |
| --email-status | stringArray | — | verified|unverified|guessed|catch_all|invalid (repeatable) |
| --employees | stringArray | — | Company size band, e.g. 51-200 (repeatable) |
| --exclude-title | stringArray | — | Title must NOT contain (repeatable) |
| --has-email | bool | — | Only rows where an address EXISTS (you still have to reveal it) |
| --has-phone | bool | — | Only rows where a phone number exists |
| --industry | stringArray | — | Industry, e.g. "Computer Software" (repeatable) |
| --keyword | stringArray | — | Company keyword, substring match (repeatable) |
| --min-score | int | — | Minimum quality score |
| --q | string | — | Free text over name, title and company |
| --seniority | stringArray | — | founder|c_suite|vp|director|manager|senior|entry (repeatable) |
| --title | stringArray | — | Title 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)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --limit | int | 100 | Maximum saved leads to return (max 500) |
| --status | string | — | Filter 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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 search
Search the global pool (people, or companies with --companies)
Search the global prospect pool.
Addresses come back MASKED. A masked address is not an address — reveal it (which spends quota) before it is of any use, and never treat the mask as something you can send to.
Paging is keyset-based and the cursor is OPAQUE: pass back exactly what the server gave you, and never reuse one after changing the sort or the filters.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --all | bool | — | Walk every page (stops after 200 pages and says so) |
| --companies | bool | — | Search companies instead of people |
| --country | stringArray | — | ISO-2 country, e.g. AU (repeatable) |
| --cursor | string | — | Opaque cursor from a previous page — never edit one, and never reuse it after changing --sort or a filter |
| --department | stringArray | — | engineering|sales|marketing|finance|hr|ops|legal|executive (repeatable) |
| --desc | bool | — | Sort descending (default: descending for score/employees, ascending for text columns) |
| --domain | stringArray | — | Company domain, e.g. canva.com (repeatable) |
| --email-status | stringArray | — | verified|unverified|guessed|catch_all|invalid (repeatable) |
| --employees | stringArray | — | Company size band, e.g. 51-200 (repeatable) |
| --exclude-title | stringArray | — | Title must NOT contain (repeatable) |
| --has-email | bool | — | Only rows where an address EXISTS (you still have to reveal it) |
| --has-phone | bool | — | Only rows where a phone number exists |
| --industry | stringArray | — | Industry, e.g. "Computer Software" (repeatable) |
| --keyword | stringArray | — | Company keyword, substring match (repeatable) |
| --limit | int | 25 | Rows per page (max 100) |
| --min-score | int | — | Minimum quality score |
| --q | string | — | Free text over name, title and company |
| --seniority | stringArray | — | founder|c_suite|vp|director|manager|senior|entry (repeatable) |
| --sort | string | "score" | Sort field — people: score|name|title|company|location|employees|email; companies: score|name|employees|industry|location |
| --title | stringArray | — | Title contains (repeatable, OR'd) |
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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --country | stringArray | — | ISO-2 country, e.g. AU (repeatable) |
| --department | stringArray | — | engineering|sales|marketing|finance|hr|ops|legal|executive (repeatable) |
| --domain | stringArray | — | Company domain, e.g. canva.com (repeatable) |
| --email-status | stringArray | — | verified|unverified|guessed|catch_all|invalid (repeatable) |
| --employees | stringArray | — | Company size band, e.g. 51-200 (repeatable) |
| --exclude-title | stringArray | — | Title must NOT contain (repeatable) |
| --has-email | bool | — | Only rows where an address EXISTS (you still have to reveal it) |
| --has-phone | bool | — | Only rows where a phone number exists |
| --industry | stringArray | — | Industry, e.g. "Computer Software" (repeatable) |
| --keyword | stringArray | — | Company keyword, substring match (repeatable) |
| --min-score | int | — | Minimum quality score |
| --name | string | — | Name for the saved search (required) |
| --q | string | — | Free text over name, title and company |
| --seniority | stringArray | — | founder|c_suite|vp|director|manager|senior|entry (repeatable) |
| --title | stringArray | — | Title 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --notes | string | — | Replace the notes |
| --status | string | — | New status |
vxcli salesshift lists
6 commandsaliases:audiencesContact lists — the audiences campaigns and sequences send to
vxcli salesshift lists add-members <list-id>
Add contacts to a list
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contacts | string | — | Contact ids, comma separated |
vxcli salesshift lists create
Create a static list
| Flag | Type | Default | What it does |
|---|---|---|---|
| --description | string | — | What it is for |
| --name | string | — | List name |
vxcli salesshift lists delete <list-id>
Delete a list (the contacts on it are not deleted)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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, signalsThe 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --message | string | — | Your pitch (required) |
| --message-file | string | — | Read the pitch from a file |
| --rate | string | — | Proposed 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --category | string | — | Filter by category |
| --limit | int | 25 | Rows to return |
| --min-score | int | — | Minimum relevance score |
| --q | string | — | Substring match on title, company, description or email |
| --saved | bool | — | Only signals saved by this workspace |
| --signal-type | string | — | job_posting | service_request | freelancer_available |
| --source | string | — | hackernews | 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --budget-max | float | — | Budget ceiling |
| --budget-min | float | — | Budget floor |
| --category | string | — | Category |
| --company | string | — | Company name |
| --contact-email | string | — | Where applicants should write |
| --description | string | — | What you need (required) |
| --location | string | — | Location or Remote |
| --skills | string | — | Comma-separated skills |
| --title | string | — | Signal 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:quotePriced 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}]
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company | string | — | Company id |
| --contact | string | — | Contact id |
| --currency | string | "USD" | Currency |
| --deal | string | — | Deal id |
| --lines-file | string | — | JSON array of line items |
| --title | string | — | Quote title |
| --valid-until | string | — | YYYY-MM-DD |
vxcli salesshift quotes decline <quote-id>
Decline internal approval
| Flag | Type | Default | What it does |
|---|---|---|---|
| --reason | string | — | Why approval was declined |
vxcli salesshift quotes delete <quote-id>
Delete a quote
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --to | string | — | Override the recipient |
vxcli salesshift quotes set-lines <quote-id>
Replace a quote's line items from a JSON file
| Flag | Type | Default | What it does |
|---|---|---|---|
| --lines-file | string | — | JSON 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 commandsSaved 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --format | string | "csv" | csv | xlsx |
| --out | string | — | Where 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}
| Flag | Type | Default | What it does |
|---|---|---|---|
| --config-file | string | — | JSON report config |
| --dataset | string | — | Dataset key |
vxcli salesshift reports save
Save a report
The server compiles it first — a report that cannot run is never saved.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --config-file | string | — | JSON report config |
| --dataset | string | — | Dataset key |
| --name | string | — | Report name |
vxcli salesshift reports schedule <report-id>
Email a saved report on a cadence
| Flag | Type | Default | What it does |
|---|---|---|---|
| --cadence | string | — | daily | weekly | monthly |
| --to | string | — | Recipients, comma separated |
vxcli salesshift reports schedules <report-id>
Delivery schedules for a saved report
vxcli salesshift seo
12 commandsSite audits, keyword tracking and rank checks
vxcli salesshift seo add-keyword
Track one or more keywords
| Flag | Type | Default | What it does |
|---|---|---|---|
| --country | string | "us" | Country code |
| --device | string | "desktop" | desktop | mobile |
| --keyword | string | — | Keyword(s), comma separated |
| --site | string | — | Site id |
vxcli salesshift seo add-site
Track a site
| Flag | Type | Default | What it does |
|---|---|---|---|
| --domain | string | — | Domain to track |
| --name | string | — | Friendly name |
vxcli salesshift seo audit
Crawl a site and score it
Runs on the tenant node, stores the result and notifies the workspace.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --max-pages | int | 20 | Pages to crawl (1–50) |
| --site | string | — | Site id |
| --url | string | — | Audit this URL directly |
vxcli salesshift seo audit-show <audit-id>
One audit in full
vxcli salesshift seo audits
Past audits
| Flag | Type | Default | What it does |
|---|---|---|---|
| --site | string | — | Site 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --site | string | — | Site 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --country | string | "us" | Country code |
| --seed | string | — | Seed phrase |
vxcli salesshift sequences
17 commandsaliases:sequence, seqMulti-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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --body | string | — | Step HTML body |
| --body-file | string | — | Read the step body from a file |
| --delay-days | int | — | Days to wait before this step |
| --subject | string | — | Step 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --body | string | — | Step HTML body |
| --body-file | string | — | Read the step body from a file |
| --delay-days | int | — | Days to wait before this step |
| --description | string | — | What it does |
| --name | string | — | Sequence name |
| --subject | string | — | Step 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contacts | string | — | Contact 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --q | string | — | Search name and description |
| --status | string | — | draft | 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contact | string | — | Render for this contact |
| --step | string | — | Step 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --steps | string | — | Step 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift settings
5 commandsaliases:configWorkspace 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| string | — | Address to suppress | |
| --reason | string | "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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift settings team [command]
Workspace members
vxcli salesshift settings team invite
Invite a teammate
| Flag | Type | Default | What it does |
|---|---|---|---|
| string | — | Who to invite | |
| --role | string | — | Role |
vxcli salesshift settings team list
Who is on this workspace
vxcli salesshift social
5 commandsaliases:distributeSocial 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
| Flag | Type | Default | What it does |
|---|---|---|---|
| --channels | string | — | Comma-separated channel keys |
| --concurrency | int | — | Max parallel channels (0 = all at once) |
| --content | string | — | Post body (required) |
| --distribute | bool | — | Distribute immediately after creating |
| --hashtags | string | — | Comma-separated hashtags |
| --images | int | — | Number of attached images |
| --link | string | — | URL to include |
| --schedule | string | — | RFC3339 time — queues it for the Celery worker |
| --title | string | — | Internal title |
vxcli salesshift social posts
List posts and their delivery outcomes
vxcli salesshift social send <post-id>
Distribute (or re-distribute) an existing post
| Flag | Type | Default | What it does |
|---|---|---|---|
| --concurrency | int | — | Max parallel channels (0 = all at once) |
vxcli salesshift social stats
Distribution totals for this workspace
SalesShift dashboard stats (contacts, deals, email funnel)
vxcli salesshift stats
SalesShift dashboard stats (contacts, deals, email funnel)
vxcli salesshift subscriptions
6 commandsaliases:subs, recurringYour customers' recurring revenue (NOT your own SalesShift plan)
vxcli salesshift subscriptions cancel <subscription-id>
Cancel a subscription
| Flag | Type | Default | What it does |
|---|---|---|---|
| --at-period-end | bool | true | Keep it running until the period closes (false stops it today) |
| --reason | string | — | Churn reason |
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift subscriptions create
Start a subscription
--items-file takes a JSON array: [{"product_id":"…","quantity":2,"unit_price_cents":5000}]
| Flag | Type | Default | What it does |
|---|---|---|---|
| --company | string | — | Company id |
| --contact | string | — | Contact id |
| --currency | string | "USD" | Currency |
| --interval | string | "month" | month | year |
| --items-file | string | — | JSON 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 commandsTasks — description, due date, owner and target goal
vxcli salesshift tasks add
Create a task
| Flag | Type | Default | What it does |
|---|---|---|---|
| --description | string | — | What to do |
| --due | string | — | Due date (RFC3339 or YYYY-MM-DD) |
| --goal | string | — | Target goal / delivery — what does done look like? |
| --priority | string | "medium" | low | medium | high |
| --progress | int | — | 0–100 |
| --title | string | — | Task title (required) |
| --type | string | "todo" | todo | call | email | meeting |
vxcli salesshift tasks delete <task-id>
Delete a task
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip the confirmation prompt |
vxcli salesshift tasks done <task-id>
Mark a task complete (progress goes to 100)
vxcli salesshift tasks list
List tasks
| Flag | Type | Default | What it does |
|---|---|---|---|
| --priority | string | — | low | medium | high |
| --status | string | — | open | done | cancelled |
| --type | string | — | todo | 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --description | string | — | New description |
| --due | string | — | New due date (RFC3339 or YYYY-MM-DD) |
| --goal | string | — | New target goal / delivery |
| --priority | string | — | low | medium | high |
| --progress | int | — | 0–100 |
| --status | string | — | open | done | cancelled |
| --title | string | — | New title |
| --type | string | — | todo | call | email | meeting |
vxcli salesshift webmaster
4 commandsaliases:seoInspect a live URL, robots.txt and sitemap.xml
vxcli salesshift webmaster generate <domain>
Generate robots.txt and sitemap.xml
| Flag | Type | Default | What it does |
|---|---|---|---|
| --disallow | string | "/api/,/admin/" | Comma-separated Disallow rules |
| --paths | string | "/" | 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
Tenant email-worker operations
vxcli salesshift worker health
Health of the tenant node email worker
vxcli salesshift workflows
11 commandsaliases:workflow, automationsAutomation 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)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --description | string | — | What it does |
| --name | string | — | Workflow name |
| --trigger | string | — | Trigger type |
vxcli salesshift workflows delete <id>
Delete a workflow and its run history
| Flag | Type | Default | What it does |
|---|---|---|---|
| --yes | bool | — | Skip 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)
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contacts | string | — | Contact ids, comma separated |
vxcli salesshift workflows list
List workflows
| Flag | Type | Default | What it does |
|---|---|---|---|
| --status | string | — | draft | 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.
| Flag | Type | Default | What it does |
|---|---|---|---|
| --contact | string | — | Run against this contact instead of a sample |
| --live | bool | — | Really 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.
| Command | Status | Why |
|---|---|---|
| leads erasure | not run | Global 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 activate | not run | The 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 detach | not run | There was no node registered to detach, and detaching a real one stops that tenant sending until another is registered. |
| billing node register <host> | refusals only | All 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.