- 1
Install the CLI
The FirstSales CLI is an npm package. Install it globally to get the
firstsalesbinary:npm install -g @firstsales.io/cli firstsales --version - 2
Authenticate
Create a Developer API key in Settings → API, then give the CLI the key and base URL. The cleanest way is environment variables:
export FIRSTSALES_API_KEY="fs-key-..." export FIRSTSALES_BASE_URL="https://api.app.firstsales.io" - 3
Verify with whoami and doctor
Before doing anything, confirm the key resolves to the right context.
whoamishows your user, org, and workspace;doctorchecks your setup:firstsales whoami --json firstsales doctor - 4
Understand the global flags
Every command shares the same flags — learn these once:
--org <id>/--workspace <id>— target scope (most commands need both).--json(default) /--pretty— output format.--data '<json>'/--data-file <path>— request body.--idempotency-key <key>— safe retries on creates.--dry-run— preview the request without sending it.--confirm— required for any destructive (delete) command.--api-key/--base-url/--profile— override auth per call.
- 5
Discover your org and workspace
Most commands are scoped to an org and workspace. List them, then reuse the IDs:
firstsales organizations list firstsales workspaces list --org ORG_ID firstsales campaigns list --org ORG_ID --workspace WS_ID - 6
Make a safe first mutation
Follow the golden loop: inspect first, mutate deliberately, verify after. Preview with
--dry-run, then create with an idempotency key, then re-read to confirm:# Preview — no write happens firstsales contacts create --org ORG_ID --workspace WS_ID \ --data '{"email":"jane@acme.com","first_name":"Jane"}' --dry-run # Create for real, idempotently firstsales contacts create --org ORG_ID --workspace WS_ID \ --data '{"email":"jane@acme.com","first_name":"Jane"}' \ --idempotency-key jane-acme-2026-01 # Verify firstsales contacts list --org ORG_ID --workspace WS_ID - 7
Delete deliberately
Destructive commands refuse to run without
--confirm— this is intentional friction so an agent or a fat-fingered command can't wipe data by accident:firstsales contacts delete --org ORG_ID --workspace WS_ID \ --contact CONTACT_ID --confirm
Pro tips
Hard-won shortcuts that keep warm-up on track.
Inspect first, mutate deliberately, verify after
The CLI is built around this loop. List before you change, --dry-run the change, run it, then re-read to confirm. It's slower to type and far cheaper than undoing a bad write.
--json is for machines, --pretty is for you
Output defaults to compact JSON so scripts and agents can parse it. Add --pretty when a human is reading, but keep --json in pipelines.
Never echo your key
Pass auth via FIRSTSALES_API_KEY or a profile, not inline where it lands in shell history or logs. The CLI never prints raw keys — don't undo that by echoing the env var.
Idempotency keys are free insurance
Any create that might be retried should carry --idempotency-key. A replayed command becomes a no-op instead of a duplicate.
Frequently asked questions
How do I install the CLI?
npm install -g @firstsales.io/cli, which gives you the firstsales binary. It maps directly to the public /api/v1 Developer API.
How does authentication work?
Set FIRSTSALES_API_KEY (and optionally FIRSTSALES_BASE_URL) in your environment, or pass --api-key / --base-url per command. Verify with firstsales whoami --json.
Why do commands need --org and --workspace?
Resources are scoped to an organization and workspace. List them with organizations list and workspaces list --org ORG_ID, then pass both IDs on scoped commands.
What does --dry-run do?
It prints the request the CLI would send without actually sending it — so you can confirm the body and target before a real mutation.
Why won't my delete run?
Destructive commands require the --confirm flag by design. Add --confirm once you're sure — it's the safety catch that stops accidental deletions.
Is the CLI different from the API?
It's a thin wrapper over the same public /api/v1 endpoints. The CLI adds convenience — centralized auth, stable JSON, idempotency handling, and destructive-op confirmation — so agents and scripts don't reimplement it.
Can I keep multiple accounts configured?
Yes — use --profile <name> to load a saved local profile, or override --api-key/--base-url per command to switch between orgs or environments.
Ready to put this into practice?
Start your FirstSales trial and launch a warmed, authenticated mailbox in minutes.
Start for $1