RevSure CLI — User Guide
1. What the CLI is
The RevSure CLI (revsure) is a command-line client for your RevSure deployment. Every command talks directly to your RevSure tenant and prints the result as JSON on standard output. There is no separate API to learn: the commands available to you are generated from your own tenant's capabilities, so the CLI always reflects exactly what your deployment supports.
Where the CLI comes into play
Because it is non-interactive, prints JSON, and reports precise exit codes, the same tool serves very different uses:
Ad-hoc analysis at the terminal — pull pipeline, attribution, or account data in seconds without opening the UI.
Command sequences and scripts — chain commands together, feed one command's output into the next, loop over a list of accounts, and keep frequently-used queries in version control as scripts your whole team can run.
Production data pipelines — scheduled extracts that land RevSure data in a warehouse, object storage, or a BI tool.
CI/CD and scheduled jobs — cron, GitHub Actions, GitLab CI, or any orchestrator, with exit codes precise enough to drive a retry policy.
Alerting and monitoring — pull a metric on a cadence, apply your own thresholds, and notify Slack or your on-call system.
AI agents and assistants — a natural tool surface for an LLM or coding agent: revsure tools and revsure describe let an agent discover what exists and each parameter's exact schema at run time, JSON output is directly parseable, and the --allow-write gate means an agent cannot change anything unless you explicitly permit it.
Internal tools and bots — back a Slack command, an internal dashboard's refresh, or a RevOps runbook.
One thing to know up front: the CLI's behaviour is identical on macOS, Windows, and Linux — same command names, same flags, same JSON output, same exit codes. What differs between operating systems is only the surrounding environment: how you install Node.js, how you set environment variables, how your shell handles quotes, and where the config file lives. Those differences are called out throughout this guide and summarised in Section 16.
2. Requirements
Checkpoint 1 — do you already have Node?
Run this first, on any operating system:
node -v
npm -v
Interpret the result:
3. Installing Node.js
Node's own instructions are always current and cover every platform, so we link to them rather than reproducing them here:
Official download page (all platforms): https://nodejs.org/en/download
npm's installation guide: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/
Choose the LTS version. Two platform-specific notes are worth knowing before you start:
Windows — reopen your terminal afterwards. PATH changes do not apply to PowerShell or Command Prompt windows that were already open. This is the single most common cause of "I installed it but it says node is not recognized".
Linux — check the version your distribution gives you. apt install nodejs on Debian and Ubuntu, and the equivalents on older RHEL derivatives, frequently install Node 12, 16, or 18 — too old, or already end-of-life. Always run node -v afterwards, and use the official instructions above if it is below what you need.
Confirm the install worked
Whichever route you took, check both commands before continuing. npm is installed alongside Node, so it should be available too — if node works but npm does not, the install is incomplete and the CLI cannot be installed.
node -v
npm -v
Both must print a version number, for example:
v24.18.1
11.6.2
If either reports command not found (macOS, Linux) or is not recognized (Windows), close the terminal and open a new one, then try again — a fresh terminal picks up the PATH the installer set. If it still fails, the install did not complete; run the official installer again.
Node's version must be 18 or higher. npm's version does not matter — whatever shipped with your Node is fine.
4. Installing the CLI
Identical on all three platforms:
npm install -g @revsure/cli
Then confirm the command is reachable:
revsure --version
This should print a version number, e.g. 0.0.3. If you get command not found or 'revsure' is not recognized, the package installed correctly but your PATH is missing npm's global directory — go to Section 17.1.
Upgrading and removing
npm install -g @revsure/cli@latest # upgrade to the newest version
npm ls -g @revsure/cli # show the installed version
npm uninstall -g @revsure/cli # remove
5. Configuring credentials
RevSure gives you three values. The CLI needs all three:
Two important warnings:
<TenantName> is case-sensitive. Use it exactly as RevSure gave it to you. A wrong case produces Realm does not exist and exit code 3.
Do not guess the client ID. It is issued alongside the secret and is not always derived from your tenant name.
5.1 Method A — environment variables
This is the recommended method. The syntax is different on every platform, which is the first real OS difference in this guide.
macOS and Linux (bash, zsh) — for the current session:
export REVSURE_URL="https://mcp.revsure.cloud/<TenantName>/mcp/"
export REVSURE_CLIENT_ID="<client-id>"
export REVSURE_CLIENT_SECRET="<client-secret>"
To make it permanent, append those three lines to your shell startup file — ~/.zshrc on modern macOS (zsh is the default), or ~/.bashrc on most Linux distributions — then run source ~/.zshrc (or source ~/.bashrc).
Windows — PowerShell (the default terminal on Windows 11), for the current session:
$env:REVSURE_URL = "https://mcp.revsure.cloud/<TenantName>/mcp/"
$env:REVSURE_CLIENT_ID = "<client-id>"
$env:REVSURE_CLIENT_SECRET = "<client-secret>"
To make it permanent for your user account:
[Environment]::SetEnvironmentVariable("REVSURE_URL", "https://mcp.revsure.cloud/<TenantName>/mcp/", "User")
[Environment]::SetEnvironmentVariable("REVSURE_CLIENT_ID", "<client-id>", "User")
[Environment]::SetEnvironmentVariable("REVSURE_CLIENT_SECRET", "<client-secret>", "User")
Then close and reopen PowerShell — persistent variables are not visible in the window that set them.
Windows — Command Prompt (cmd.exe), for the current session:
set REVSURE_URL=https://mcp.revsure.cloud/<TenantName>/mcp/
set REVSURE_CLIENT_ID=<client-id>
set REVSURE_CLIENT_SECRET=<client-secret>
Permanently, use setx (note the quotes, and that it also requires a new terminal):
setx REVSURE_URL "https://mcp.revsure.cloud/<TenantName>/mcp/"
Note on set in cmd.exe: do not put quotes around the value with set, and do not put spaces around the =. Both become part of the value.
5.2 Method B — the config file
Instead of environment variables you can use a config file. The secret is never written to this file — instead, client_secret_env names an environment variable the CLI should read the secret from. The CLI never writes your secret to disk.
The file location depends on your platform:
Contents:
{
"url": "https://mcp.revsure.cloud/<TenantName>/mcp/",
"client_id": "<client-id>",
"client_secret_env": "REVSURE_CLIENT_SECRET",
"timeout": 120
}
Fields:
The file must contain a JSON object. If it is malformed, or timeout is zero, negative, or not a number, the CLI reports a usage error (exit 2) that names the file — it will not fail silently or blame the network.
5.3 Precedence
For each of the three values independently, the CLI takes the first source that provides it:
Environment variable (REVSURE_URL, REVSURE_CLIENT_ID, REVSURE_CLIENT_SECRET)
The config file
This is per-value, so mixing is fine: you can keep url and client_id in the config file and supply only the secret through the environment. If any of the three is missing entirely, the CLI exits 2 and names exactly which ones are absent.
6. Checkpoint 2 — verify everything works
One command checks configuration, authentication, and connectivity in a single pass. Run it immediately after installing:
revsure doctor
A healthy result:
ok config resolved -- https://mcp.revsure.cloud/AcmeCorp/mcp/
ok token fetched -- ok (fresh from Keycloak)
ok server reachable + catalog fetched -- 91 tools
All checks passed.
doctor stops at the first failing step and exits with the code for the real cause, so the exit code tells you which layer is broken:
7. First run
Right after installing, run:
revsure sync
Expected output: Synced 91 tools. — the exact number depends on what your tenant has enabled.
Until you do this, revsure --help lists only the built-in commands. After it, you see everything your tenant offers. Running commands keeps the list up to date automatically, so sync is only worth running by hand right after installing, or when you know new capabilities have been enabled for you.
Then explore:
revsure tools # every command available to you
revsure describe pipeline-health-overview # full detail on one command
revsure pipeline-health-overview --quarters q0
8. Built-in commands
These six commands exist on every install regardless of tenant.
revsure tools
Lists every command available to you, one per line: the command name in kebab-case followed by the first line of its description.
revsure tools
revsure describe <tool>
Prints a JSON description of one command — its wire name, full description, whether it can make changes, and every parameter with both spellings, type, whether it's required, allowed values, and any server-side default.
Use the same kebab-case name you see in revsure tools:
revsure describe pipeline-health-overview
describe also accepts the underlying snake_case name, so a name copied out of revsure call output works here too.
Example output:
{
"name": "pipeline_health_overview",
"description": "Snapshot of open-pipeline health per closing quarter …",
"write": false,
"parameters": [
{
"name": "quarters",
"flag": "--quarters",
"type": "array",
"required": false,
"description": "Closing-quarter keys to fetch cards for. Quarter keys: 'q0' = current quarter, 'q1' = next quarter, 'q-1' = last quarter …"
},
{
"name": "opportunity_type",
"flag": "--opportunity-type",
"type": "string",
"required": false,
"description": "Opportunity Type filter. 'Overall' = all opportunities (default) …"
}
]
}
(Descriptions abridged here; describe prints them in full, and lists every parameter.)
Read it as: use flag when running the generated command; use name as the JSON key when using revsure call.
revsure call <tool> [json]
Calls a command by its underlying wire name, passing arguments as one JSON object. This bypasses flag generation entirely — useful when you already have JSON, or are generating requests programmatically.
revsure call get_funnel_stages
revsure call pipeline_health_overview '{"quarters": ["q0"]}'
Rules:
The tool name must be in snake_case. A kebab-case name is refused with exit 7 — an unrecognised name cannot be confirmed read-only, so it is treated as a write. Use describe (which accepts either form) to look up the snake_case name.
The JSON argument must be a JSON object. null, arrays, and bare scalars are rejected as usage errors (exit 2) rather than being sent to the server.
Omitting the JSON argument entirely is the same as passing {}.
call does not bypass the write gate. A write-capable command invoked through call still refuses without --allow-write.
revsure sync
Force-refreshes the local catalog of available commands and reports how many were found. See Section 7.
revsure doctor
Diagnoses configuration, authentication, and connectivity. See Section 6.
revsure auth whoami
Decodes your current access token and shows who it belongs to and how long it remains valid. Useful for confirming you are authenticated as the identity you expect.
revsure auth whoami
azp (client id): revsure-cli-acme
sub: 8f3c...
revsure.user_id: 1234
revsure.tenant_id: AcmeCorp
sid: (absent -- expected for machine tokens)
lifetime: 287s remaining
sid being absent is normal and expected for machine (client-credentials) tokens.
Help and version
revsure # prints help
revsure --help # same
revsure help <command> # help for one command
revsure <command> --help # same
revsure --version # or -V
Help and version never require network access when a local catalog exists, so they work offline.
9. Generated tool commands
Beyond the six built-ins, every capability your tenant exposes becomes its own command with its own typed flags, generated from your tenant's own definitions. This means the exact list of commands you see is specific to your deployment — run revsure tools to see yours.
revsure pipeline-health-overview --quarters q0 --opportunity-type Overall
Per-command help shows every flag, its description, whether it's required, allowed values, and any server-side default:
Usage: revsure pipeline-health-overview [options]
Snapshot of open-pipeline health per closing quarter — the widget cards.
...
Options:
--quarters <value> Closing-quarter keys to fetch cards for. Quarter
keys: 'q0' = current quarter, 'q1' = next quarter,
'q-1' = last quarter ... (repeat the flag, or one
JSON array / @file.json / @- for stdin)
--opportunity-type <value> Opportunity Type filter. 'Overall' = all
opportunities (default) ...
--funnel-view <value> Metric expression: 'value' — currency (default),
'volume' — opportunity counts.
-h, --help display help for command
A flag you don't pass is not sent at all, so the server applies its own default — which is what [server default: …] in the help text is showing you.
10. Names and flags: underscores vs. hyphens
Every command has one underlying name in snake_case, e.g. pipeline_health_overview. The CLI shows it in two styles, and which one you type depends on where you're typing it.
The rule: what you type as a command or a flag is kebab-case. What travels over the wire — the call name and JSON keys — is snake_case.
The same request, both ways:
revsure pipeline-health-overview --opportunity-type Overall
revsure call pipeline_health_overview '{"opportunity_type": "Overall"}'
If you type a snake_case name where a command is expected, the CLI recognises the mistake and tells you the right form rather than just failing:
$ revsure pipeline_health_overview
Unknown command 'pipeline_health_overview'. Did you mean 'pipeline-health-overview'?
11. Flag value formats
Every flag has one of five types. revsure describe <tool> reports the type of each.
Array flags
Three interchangeable forms:
# 1. Repeat the flag
revsure pipeline-health-overview --quarters q0 --quarters q1
# 2. One JSON array
revsure pipeline-health-overview --quarters '["q0","q1"]'
# 3. From a file, or from standard input
revsure pipeline-health-overview --quarters @quarters.json
revsure pipeline-health-overview --quarters @-
You can mix forms in a single command and the values accumulate rather than overwrite — --quarters q0 --quarters '["q1"]' sends both q0 and q1.
Only a value that starts with [ or @ is treated as JSON; anything else is sent as a single literal string. So --quarters '{"a":1}' is not an error — it sends the characters {"a":1} as one array entry.
Usage errors (exit 2) naming the flag are reported for malformed JSON, a file that can't be read, and an @file whose contents are not an array.
12. Passing JSON values
Object-shaped flags, and the argument to revsure call, take a JSON value in one of three forms:
# Inline
revsure account-details --filters '[{"column":"Account Industry","operator":"IS","value":"Software"}]'
# From a file — prefix the path with @
revsure account-details --filters @filters.json
# From standard input — use @-
cat filters.json | revsure account-details --filters @-
JSON quoting differs by shell — read this if you are on Windows
Inline JSON relies on your shell passing quotes through untouched, and Windows shells do not behave like macOS and Linux shells here.
Recommendation for Windows users: use @file.json. It sidesteps shell quoting entirely and behaves identically on every platform.
# Windows — save the JSON to a file, then reference it
revsure account-details --filters @filters.json
If you prefer to pipe from standard input, note that cat is not a Command Prompt command — use type:
type filters.json | revsure account-details --filters @-
In PowerShell, Get-Content works:
Get-Content filters.json | revsure account-details --filters @-
13. Commands that make changes
Some commands can change state — sending a message, triggering an agent run, creating a segment. These are marked [write] in revsure --help and refuse to run unless you explicitly pass --allow-write:
$ revsure linkedin-send-message --target-identifier jane-doe --message "Hi!"
'linkedin_send_message' can make changes (write). Re-run with --allow-write to confirm.
# exit code 7
Add the flag to confirm. It works either before or after the command name — both forms are equivalent:
revsure --allow-write linkedin-send-message --target-identifier jane-doe --message "Hi!"
revsure linkedin-send-message --target-identifier jane-doe --message "Hi!" --allow-write
Three details worth knowing:
The gate runs before any network request. A refused write makes no call at all.
revsure call is subject to the same gate. It is an escape hatch around flag generation, not around the safety check.
A command missing from your local catalog is treated as a write, because it cannot be confirmed read-only. If the gate trips on a command you know only reads, run revsure sync and retry.
The CLI never retries a command by itself. This matters for writes: if one fails with exit 5 (network failure or timeout), the request may still have reached RevSure and taken effect. Check the resulting state before running it again. Exit codes 2, 3, 4, and 7 are unambiguous — the request was never sent.
14. Output, scripting, and exit codes
Every successful command prints its result as indented JSON to standard output. Errors go to standard error. That separation means results pipe cleanly even when something goes wrong.
revsure get-funnel-stages | jq .funnel_mapping
jq is a separate tool and is not installed by default on any of the three platforms. On macOS: brew install jq. On Debian/Ubuntu: sudo apt install jq. On Windows: winget install jqlang.jq. In PowerShell you can avoid it entirely — revsure get-funnel-stages | ConvertFrom-Json gives you a native object.
Exit codes
A script can branch on why a command failed, not merely that it did:
The distinction between 3 and 5 is deliberate: 3 means your credentials are wrong and will stay wrong; 5 means the failure is transient and worth retrying. A throttled or unhealthy identity service is reported as 5, never as 3.
A zero exit code does not always mean the request succeeded. Many commands report a problem — a missing required filter, an invalid column name — as an ordinary JSON result containing an error field, which the CLI prints and exits 0 for.
15. Files the CLI writes
The CLI keeps its state in one directory:
It holds your optional config.json (Section 5.2), cached access tokens, and a cached copy of the command catalog.
Your client secret is never written to disk by the CLI.
Deleting ~/.revsure/cache is always safe — the next command rebuilds it. This is the first thing to try if the CLI seems to be working from an out-of-date list of commands.
16. Operating system differences at a glance
The CLI itself behaves identically everywhere. Command names, flags, the kebab/snake rule, --allow-write, JSON output, and exit codes 0–7 are all platform-independent. The table below is the complete list of things that do differ.
17. Troubleshooting
17.1 command not found: revsure after a successful install
The package installed, but npm's global command directory is not on your PATH. This is common when npm has been pointed at a custom prefix to avoid sudo.
First find where npm puts global commands:
npm config get prefix
macOS and Linux — add that directory's bin subdirectory to your PATH:
echo 'export PATH="'"$(npm config get prefix)"'/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
revsure --version
Use ~/.bashrc (Linux) or ~/.bash_profile (macOS bash) instead of ~/.zshrc if you use bash.
Windows — the recipe above is shell-specific and does not apply. npm's global directory is normally %APPDATA%\npm (C:\Users\<you>\AppData\Roaming\npm). Confirm with:
npm config get prefix
Then:
First, simply close and reopen your terminal. A PATH change made by the Node installer is not visible in windows that were already open. This resolves the majority of cases.
If it still isn't found, add the directory to your user PATH: press Win and search for "Edit environment variables for your account", select Path → Edit → New, add %APPDATA%\npm, click OK, and open a new terminal.
Or from PowerShell:
[Environment]::SetEnvironmentVariable("Path", "$env:Path;$env:APPDATA\npm", "User")
Then reopen PowerShell.
17.2 EACCES: permission denied during install (macOS and Linux)
npm is trying to write to a system directory your user cannot modify. Do not fix this with sudo npm install -g — it creates root-owned files that cause further problems later.
Two supported fixes, both from npm's own documentation at https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally/:
Reinstall Node with a version manager. Global installs then land in your home directory and the problem disappears permanently. This is npm's own recommended fix; its guide covers the options for each platform.
Point npm at a directory you own:
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
npm install -g @revsure/cli
17.3 Windows: "cannot be loaded because running scripts is disabled on this system"
npm creates two shims for a global command: revsure.cmd and revsure.ps1. On Windows, PowerShell's execution policy is Restricted by default on clients, which blocks the .ps1 shim.
Check your current policy:
Get-ExecutionPolicy -List
Allow locally-created scripts for your own user account (this does not require administrator rights and does not weaken the policy for downloaded scripts):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Microsoft's reference: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy
If your organisation enforces the execution policy through Group Policy, you will not be able to change it — use Command Prompt instead, where revsure.cmd is used and the policy does not apply.
17.4 Missing required configuration: … (exit 2)
The CLI names exactly which of the three values it could not find. Most common causes:
The variables were set in a different terminal window than the one you are running in.
On Windows, they were set persistently but the terminal was not reopened.
They were set inside a script that ran in a subshell, so they never reached your session.
Verify what your session actually has:
echo $REVSURE_URL # macOS / Linux
$env:REVSURE_URL # PowerShell
echo %REVSURE_URL% REM cmd.exe
17.5 Realm does not exist or Failed to get a token (exit 3)
Your credentials were rejected. Work through these in order:
Check the tenant name's capitalisation in REVSURE_URL. It is case-sensitive — the tenant name is the part of the URL before /mcp.
Check the client ID. It is not always derived from the tenant name.
Check the secret for a truncated copy-paste or a trailing newline or space.
Check the region. An EU tenant's URL must contain -eu., or the CLI will authenticate against the US identity service.
Run revsure auth whoami — if a token is being issued, this tells you which identity it belongs to.
17.6 Exit 4 — the server rejected the token
Authentication succeeded but the MCP endpoint returned 401 or 403. Typically your client is authenticating correctly but is not authorised for that tenant or endpoint. Contact your RevSure representative with the output of revsure auth whoami.
17.7 Exit 5 — network failure or timeout
Check, in order:
Can you reach the endpoint at all? curl -I https://mcp.revsure.cloud/ (or curl.exe in PowerShell).
Are you behind a corporate proxy or a TLS-inspecting firewall? See Section 18 — this is the most common cause on managed corporate machines.
Was the message about the identity service being unavailable? That is transient — retry shortly.
Is a large request simply timing out? Raise timeout in your config file (Section 5.2).
17.8 revsure --help shows no tool commands
Expected on a fresh install. Run revsure sync (Section 7). If sync itself fails, run revsure doctor and use its exit code to find the layer at fault.
17.9 A command I expect to be read-only is blocked as a write
Your local catalog is stale or missing that command, and the CLI fails safe by treating anything it cannot confirm as read-only as a write. Run revsure sync, then retry.
18. Corporate networks: proxies and TLS inspection
On managed corporate machines the most common failure is revsure doctor failing at token fetched or server reachable with exit 5, because outbound HTTPS goes through a proxy or a TLS-inspecting appliance (Zscaler, Netskope, Blue Coat, and similar).
The CLI relies on Node's built-in HTTP client, so it is configured through Node's own environment variables. These have minimum Node version requirements — on older Node versions setting them has no effect at all, which is a confusing failure mode. This is the main practical reason to be on Node 24.
Proxy
export HTTPS_PROXY="http://proxy.company.com:8080"
export NO_PROXY=".company.com"
export NODE_USE_ENV_PROXY=1
HTTP_PROXY, HTTPS_PROXY, and NO_PROXY are only honoured when NODE_USE_ENV_PROXY=1 is also set. Requires Node 22.21.0+ or 24.0.0+.
On Windows PowerShell:
$env:HTTPS_PROXY = "http://proxy.company.com:8080"
$env:NODE_USE_ENV_PROXY = "1"
TLS inspection / custom certificate authority
If your network re-signs HTTPS traffic, you will see certificate errors. Two options:
# Trust the operating system's certificate store (recommended —
# picks up certificates your IT team has already deployed).
# Requires Node 22.19.0+ or 24.6.0+.
export NODE_USE_SYSTEM_CA=1
# Or point at a specific CA bundle. Works on all Node versions.
export NODE_EXTRA_CA_CERTS="/path/to/company-ca-bundle.pem"
Both can be set together; their trust is cumulative.
Node's official guidance on all of the above: https://nodejs.org/learn/http/enterprise-network-configuration
If your proxy requires authentication, include the credentials in the proxy URL (http://user:pass@proxy:8080). Prefer setting this in your shell profile rather than in a shared script, so credentials are not committed anywhere.
19. Known limitations
Windows: a repeated tokens.json is readable by others warning. The CLI's file-permission check uses POSIX modes, which Windows does not use, so this warning is expected on every command. It is harmless — commands succeed and your secret is still never written to disk — but Windows re-authenticates on each run, making commands slightly slower. Pending confirmation on Windows hardware.
Node 18 and 20 are end-of-life. The package's declared minimum is Node 18, but neither 18 nor 20 receives security updates any more, and the proxy and certificate options in Section 18 are unavailable on them.
Proxy configuration requires newer Node. As noted above, NODE_USE_ENV_PROXY needs Node 22.21+/24+ and NODE_USE_SYSTEM_CA needs 22.19+/24.6+. On older versions these variables are silently ignored.
20. Quick reference
Environment variables
Commands
Setup, end to end
node -v # 1. need v18+, v24 recommended
npm install -g @revsure/cli # 2. install
export REVSURE_URL=... # 3. configure (see Section 5
export REVSURE_CLIENT_ID=... # for Windows syntax)
export REVSURE_CLIENT_SECRET=...
revsure doctor # 4. verify
revsure sync # 5. load your command catalog
revsure tools # 6. see what you can do
21. Support and licence
The RevSure CLI is proprietary software. Use is limited to RevSure customers under an active agreement — see the LICENSE.md file included with the package.
For questions, issues, or access to the CLI, contact your RevSure representative. When reporting a problem, please include:
The output of revsure --version and node -v
Your operating system and shell
The full output of revsure doctor
The exact command you ran and its exit code