@firstsales.io/cli
v0.1.2
Published
Command-line interface for the FirstSales Developer API.
Downloads
404
Maintainers
Readme
@firstsales.io/cli
Control FirstSales from Codex, Claude Code, Gemini, Claude.ai, CI, scripts, and your terminal.
"Inspect first. Mutate deliberately. Verify after every action."
A thin, JSON-first CLI over the FirstSales Developer API. 122 commands. No runtime dependencies. Built for agent-safe automation.
Why · How It Works · Quick Start · Commands · Use Cases · Safety
AUTH INSPECT MUTATE VERIFY
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ API Key │ │ whoami │ │ campaigns │ │ re-read │
│ Base URL │──▶ │ list/get │──▶ │ contacts │──▶ │ logs │
│ org/ws │ │ analytics │ │ inbox │ │ status │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
firstsales firstsales firstsales firstsales
whoami campaigns list contacts create campaigns get
doctor contacts get inbox reply api-keys list
SAFE BY DEFAULT
┌───────────────────────────────────────────────────────────────────────┐
│ JSON output · explicit scopes · idempotency keys · dry-run previews │
│ destructive --confirm · stable exit codes · no raw/hashed key output │
└───────────────────────────────────────────────────────────────────────┘Why This Exists
FirstSales can be managed from the web app, but AI coding agents and internal automation need a stable interface that does not depend on app-private routes.
@firstsales.io/cli is the terminal and agent surface for the FirstSales Developer API:
- Codex / Claude Code: inspect state, update campaigns, import contacts, approve drafts, and verify results from a shell.
- Gemini / CI: parse stable JSON and react to predictable exit codes.
- Claude.ai / no-shell contexts: use the same API contract from the docs and copyable cURL workflows.
- Operators: run repeatable campaign, inbox, connector, billing, team, and API-key workflows.
The CLI is intentionally boring. It does not contain business logic. It maps commands to /api/v1 endpoints and lets the API enforce auth, scopes, tenant isolation, rate limits, idempotency, and redaction.
How It Works
COMMAND FLOW:
1. Load config from flags, env, or profile.
2. Resolve base URL and Developer API key.
3. Build the public /api/v1 request.
4. Add JSON body, idempotency key, org, workspace, and path params.
5. Refuse destructive commands unless --confirm is present.
6. Send the request with Authorization: Bearer <key>.
7. Print compact JSON by default or pretty JSON with --pretty.
8. Exit with a stable code for scripts and agents.Design Rules
| Rule | What it means |
| --- | --- |
| Thin client | The CLI calls the Developer API. It does not duplicate FirstSales business logic. |
| JSON-first | Output defaults to machine-readable JSON for agents and scripts. |
| Read before write | Agents should use whoami, list, and get before mutations. |
| Explicit destructive actions | DELETE commands require --confirm. |
| Retry-safe writes | Use --idempotency-key for imports, approvals, lifecycle actions, and other retryable writes. |
| No secret output | Raw API keys, hashed keys, provider tokens, SMTP passwords, and connector secrets are not printed. |
| Stable public contract | Only /api/v1 endpoints are supported. App-private routes are intentionally ignored. |
Quick Start
Install
npm install -g @firstsales.io/cliPackage page:
https://www.npmjs.com/package/@firstsales.io/cliSource repository:
https://github.com/firstsalesio/firstsales-cliConfigure
Use environment variables for agents and CI:
export FIRSTSALES_API_KEY="<YOUR_FIRSTSALES_API_KEY>"
export FIRSTSALES_BASE_URL="https://api.app.firstsales.io"Or pass flags:
firstsales whoami \
--api-key "<YOUR_FIRSTSALES_API_KEY>" \
--base-url "https://api.app.firstsales.io" \
--jsonVerify Identity
firstsales whoami --jsonwhoami is the FirstSales equivalent of npm whoami: it validates the active token and prints the user/key/org/workspace context without exposing raw or hashed keys.
Check Setup
firstsales doctor --prettyFirst Read
firstsales orgs list --json
firstsales workspaces list --org org_123 --json
firstsales campaigns list --org org_123 --workspace ws_123 --jsonFirst Safe Mutation
firstsales contacts create \
--org org_123 \
--workspace ws_123 \
--data '{"email":"[email protected]","firstName":"Alex"}' \
--idempotency-key import-row-001 \
--jsonDestructive Mutation
firstsales contacts delete \
--org org_123 \
--workspace ws_123 \
--contact contact_123 \
--confirm \
--jsonConfiguration
Environment Variables
| Variable | Purpose |
| --- | --- |
| FIRSTSALES_API_KEY | Developer API key used for bearer auth. |
| FIRSTSALES_BASE_URL | API base URL. Defaults to https://api.app.firstsales.io. |
| FIRSTSALES_PROFILE | Profile name to load from the local profile config. |
Profile File
Profiles are useful on a developer machine. Prefer env vars for CI and agents.
{
"currentProfile": "prod",
"profiles": {
"prod": {
"apiKey": "<YOUR_FIRSTSALES_API_KEY>",
"baseUrl": "https://api.app.firstsales.io"
},
"staging": {
"apiKey": "<YOUR_STAGING_FIRSTSALES_API_KEY>",
"baseUrl": "https://staging-api.app.firstsales.io"
}
}
}Auth Resolution Order
--api-keyFIRSTSALES_API_KEY- selected local profile
Base URL Resolution Order
--base-urlFIRSTSALES_BASE_URL- selected local profile
https://api.app.firstsales.io
Global Flags
| Flag | Applies to | Purpose |
| --- | --- | --- |
| --api-key <key> | all API commands | Use a specific Developer API key. |
| --base-url <url> | all API commands | Override the API base URL. |
| --profile <name> | all API commands | Load a named local profile. |
| --org <id> | organization/workspace commands | Fill {org} path parameters. |
| --workspace <id> | workspace commands | Fill {workspace} path parameters. |
| --json | all commands | Emit compact JSON. This is the default. |
| --pretty | all commands | Emit formatted JSON. |
| --data '<json>' | mutating commands | Provide a JSON request body. |
| --data-file <path> | mutating commands | Read a JSON request body from disk. |
| --idempotency-key <key> | retryable mutations | Send an idempotency key. |
| --dry-run | API commands | Print method, URL, and body without sending the request. |
| --confirm | destructive commands | Required for destructive commands. |
| --output <json\|table\|tsv> | all commands | Choose output format. Defaults to table on a TTY, json when piped. |
| --page <n> / --limit <n> | list commands | Page through results manually. |
| --all | GET list commands | Auto-paginate and concatenate every page. |
Exit Codes
| Code | Meaning |
| --- | --- |
| 0 | ok |
| 1 | runtime error |
| 2 | usage error |
| 3 | auth error |
| 4 | not found |
| 5 | rate limited |
Breaking in 0.1.1: exit codes were redefined from the 0.1.0 scheme. Scripts that branch on exit codes must migrate.
Auth Profiles
Store named API key/base URL profiles locally instead of exporting env vars every session:
firstsales auth login --profile prod --api-key "<YOUR_FIRSTSALES_API_KEY>" --base-url "https://api.app.firstsales.io"
firstsales auth status --profile prod --json
firstsales auth logout --profile prodUse --profile <name> (or FIRSTSALES_PROFILE) on any command to select a saved profile. auth status never prints the raw key.
Shell Completions
# bash
firstsales completion bash >> ~/.bashrc
# zsh
firstsales completion zsh >> ~/.zshrc
# fish
firstsales completion fish > ~/.config/fish/completions/firstsales.fishAPI Escape Hatch
Call any public /api/v1 route directly, signed with the active key, even before a dedicated command exists:
firstsales api GET /api/v1/organizations/org_123/workspaces --json
firstsales api POST /api/v1/organizations/org_123/workspaces/ws_123/campaigns --data '{"name":"New Campaign"}' --jsonSafety Model
API Key Safety
FirstSales Developer API keys are scoped and access-level aware.
- Workspace keys can only operate workspace-scoped resources.
- Organization keys need explicit organization scopes.
- Revoked keys fail immediately.
- Keys fail closed if the creator loses org access or is suspended.
- Raw keys are shown only once at creation and are never retrievable later.
CLI Safety
| Protection | Behavior |
| --- | --- |
| Destructive guard | Commands marked destructive stop unless --confirm is passed. |
| Dry run | --dry-run previews the HTTP request without auth or network calls. |
| Idempotency | --idempotency-key sends retry protection for supported mutations. |
| Redaction | API errors and identity output do not print raw or hashed keys. |
| Unsupported surfaces | Signals and webhooks return unsupported_operation until public API support exists. |
| Stable errors | Non-zero exits return JSON errors that agents can parse. |
Recommended Agent Loop
1. firstsales whoami --json
2. Read org/workspace/resource state.
3. Plan the smallest mutation.
4. Use --dry-run when useful.
5. Use --idempotency-key for retryable writes.
6. Use --confirm only for intentional destructive commands.
7. Re-read state and verify the result.Use Cases
Campaign Operations
firstsales campaigns list --org org_123 --workspace ws_123 --json
firstsales campaigns get --org org_123 --workspace ws_123 --campaign camp_123 --json
firstsales campaigns pause --org org_123 --workspace ws_123 --campaign camp_123 --json
firstsales campaigns resume --org org_123 --workspace ws_123 --campaign camp_123 --json
firstsales campaigns analytics --org org_123 --workspace ws_123 --campaign camp_123 --jsonUse this for campaign audits, status checks, lifecycle changes, reporting, and agent-driven campaign monitoring.
Contact Import and Cleanup
firstsales contacts create \
--org org_123 \
--workspace ws_123 \
--data '{"email":"[email protected]","firstName":"Alex"}' \
--idempotency-key [email protected] \
--json
firstsales contact-tags list --org org_123 --workspace ws_123 --json
firstsales contacts delete --org org_123 --workspace ws_123 --contact contact_123 --confirmUse this for CRM syncs, enrichment pipelines, list cleanup, tag maintenance, imports, and exports.
Inbox Review
firstsales inbox threads --org org_123 --workspace ws_123 --json
firstsales inbox thread --org org_123 --workspace ws_123 --thread thread_123 --json
firstsales inbox approve-draft --org org_123 --workspace ws_123 --email email_123 --idempotency-key approve-email-123
firstsales inbox reject-draft --org org_123 --workspace ws_123 --email email_123 --jsonUse this for reply monitoring, draft approval queues, human-in-the-loop workflows, and read-state sync.
Copilot (Non-Interactive)
firstsales copilot ask "Summarize this week's campaign performance" \
--org org_123 --workspace ws_123 --jsonPosts a prompt, polls the session, and prints only the assistant's reply text on stdout (safe to pipe). Progress and approval prompts go to stderr. --auto-approve is best-effort only: the CLI logs an audit line and the server (not the CLI) makes the final approval decision; if the turn is still pending after that, the CLI exits 1 instead of polling to timeout. Use --no-wait to return immediately with {sessionId, messageId}, and --session <id> to continue an existing session.
Connector Health
firstsales connectors list --org org_123 --workspace ws_123 --json
firstsales connectors test --org org_123 --workspace ws_123 --connector conn_123 --jsonUse this for deliverability checks, sender health diagnostics, and setup validation. Connector responses never return provider secrets.
Knowledge Base and Offerings
firstsales kb list --org org_123 --workspace ws_123 --json
firstsales kb query --org org_123 --workspace ws_123 --kb kb_123 --data '{"query":"What problems do we solve?"}'
firstsales offerings list --org org_123 --workspace ws_123 --jsonUse this to keep sales context current and to let agents retrieve approved positioning before writing or replying.
Tracking Domains
firstsales tracking-domains list --org org_123 --workspace ws_123 --json
firstsales tracking-domains verify --org org_123 --workspace ws_123 --domain domain_123 --jsonUse this for deliverability setup and domain verification checks.
Billing and Credits
firstsales billing overview --org org_123 --json
firstsales billing credits --org org_123 --json
firstsales billing usage-summary --org org_123 --json
firstsales billing checkout --org org_123 --idempotency-key checkout-org-123-001 --jsonUse this for spend reporting, credit monitoring, and safe checkout/top-up link creation.
Team Administration
firstsales members list --org org_123 --json
firstsales invitations create --org org_123 --data '{"email":"[email protected]","role":"member"}' --json
firstsales groups create --org org_123 --data '{"name":"SDR Team"}' --json
firstsales domains add --org org_123 --data '{"domain":"example.com"}' --jsonUse this for onboarding, group management, and domain allowlist automation.
API Key Rotation
firstsales api-keys list --org org_123 --json
firstsales api-keys create \
--org org_123 \
--data '{"name":"Codex automation","scopes":["campaigns:read","contacts:write"],"accessLevel":"workspace"}' \
--json
firstsales api-keys revoke --org org_123 --key key_123 --confirm --jsonUse this for scoped automation keys, stale-key cleanup, and incident response.
Complete Command Reference
Every command maps to a public Developer API endpoint. Commands marked destructive require --confirm.
| Command | Method | Public API path | Destructive | Required placeholders |
| --- | --- | --- | --- | --- |
| whoami | GET | /api/v1/whoami | no | - |
| doctor | GET | /api/v1/whoami | no | - |
| orgs list | GET | /api/v1/organizations | no | - |
| organizations list | GET | /api/v1/organizations | no | - |
| workspaces list | GET | /api/v1/organizations/{org}/workspaces | no | org |
| campaigns list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns | no | org, workspace |
| campaigns create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns | no | org, workspace |
| campaigns get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign} | no | campaign |
| campaigns update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign} | no | campaign |
| campaigns start | POST | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/actions/start | no | campaign |
| campaigns pause | POST | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/actions/pause | no | campaign |
| campaigns resume | POST | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/actions/resume | no | campaign |
| campaigns progress | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/progress | no | campaign |
| campaigns analytics | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/analytics | no | campaign |
| campaigns events | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/events | no | campaign |
| campaigns sources | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/sources | no | campaign |
| campaigns workflow | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/workflow | no | campaign |
| campaigns workflow-update | PUT | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/workflow | no | campaign |
| contacts list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contacts | no | org, workspace |
| contacts create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/contacts | no | org, workspace |
| contacts get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contacts/{contact} | no | contact |
| contacts update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/contacts/{contact} | no | contact |
| contacts delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/contacts/{contact} | yes | contact |
| contact-lists list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contact-lists | no | org, workspace |
| contact-lists create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/contact-lists | no | org, workspace |
| contact-lists update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/contact-lists/{list} | no | list |
| contact-lists delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/contact-lists/{list} | yes | list |
| contact-tags list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contact-tags | no | org, workspace |
| contact-tags rename | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/contact-tags/rename | no | org, workspace |
| contact-tags delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/contact-tags | yes | org, workspace |
| contact-imports create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/contact-imports | no | org, workspace |
| contact-exports list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contact-exports | no | org, workspace |
| inbox threads | GET | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/threads | no | org, workspace |
| inbox thread | GET | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/threads/{thread} | no | thread |
| inbox reply | POST | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/threads/{thread}/reply | no | thread |
| inbox read | POST | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/threads/{thread}/read | no | thread |
| inbox approve-draft | POST | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/drafts/{email}/approve | no | email |
| inbox reject-draft | POST | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/drafts/{email}/reject | no | email |
| connectors list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/connectors | no | org, workspace |
| connectors delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/connectors/{connector} | yes | connector |
| connectors test | POST | /api/v1/organizations/{org}/workspaces/{workspace}/connectors/{connector}/test | no | connector |
| kb list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/knowledge-bases | no | org, workspace |
| kb create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/knowledge-bases | no | org, workspace |
| kb get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/knowledge-bases/{kb} | no | kb |
| kb update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/knowledge-bases/{kb} | no | kb |
| kb delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/knowledge-bases/{kb} | yes | kb |
| kb query | POST | /api/v1/organizations/{org}/workspaces/{workspace}/knowledge-bases/{kb}/query | no | kb |
| offerings list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/offerings | no | org, workspace |
| offerings create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/offerings | no | org, workspace |
| offerings get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/offerings/{offering} | no | offering |
| offerings update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/offerings/{offering} | no | offering |
| offerings delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/offerings/{offering} | yes | offering |
| tracking-domains list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/tracking-domains | no | org, workspace |
| tracking-domains create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/tracking-domains | no | org, workspace |
| tracking-domains delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/tracking-domains/{domain} | yes | domain |
| tracking-domains verify | POST | /api/v1/organizations/{org}/workspaces/{workspace}/tracking-domains/{domain}/verify | no | domain |
| billing overview | GET | /api/v1/organizations/{org}/billing | no | org |
| billing credits | GET | /api/v1/organizations/{org}/billing/credits | no | org |
| billing usage-summary | GET | /api/v1/organizations/{org}/billing/credits/usage-summary | no | org |
| billing credit-history | GET | /api/v1/organizations/{org}/billing/credits/history | no | org |
| billing payments | GET | /api/v1/organizations/{org}/billing/payments | no | org |
| billing top-ups | GET | /api/v1/organizations/{org}/billing/top-ups | no | org |
| billing checkout | POST | /api/v1/organizations/{org}/billing/checkout | no | org |
| billing top-up | POST | /api/v1/organizations/{org}/billing/top-up | no | org |
| members list | GET | /api/v1/organizations/{org}/members | no | org |
| invitations list | GET | /api/v1/organizations/{org}/invitations | no | org |
| invitations create | POST | /api/v1/organizations/{org}/invitations | no | org |
| invitations cancel | DELETE | /api/v1/organizations/{org}/invitations/{invitation} | yes | org, invitation |
| groups list | GET | /api/v1/organizations/{org}/groups | no | org |
| groups create | POST | /api/v1/organizations/{org}/groups | no | org |
| groups update | PATCH | /api/v1/organizations/{org}/groups/{group} | no | org, group |
| groups delete | DELETE | /api/v1/organizations/{org}/groups/{group} | yes | org, group |
| domains list | GET | /api/v1/organizations/{org}/domains | no | org |
| domains add | POST | /api/v1/organizations/{org}/domains | no | org |
| domains remove | DELETE | /api/v1/organizations/{org}/domains/{domain} | yes | org, domain |
| api-keys list | GET | /api/v1/organizations/{org}/api-keys | no | org |
| api-keys create | POST | /api/v1/organizations/{org}/api-keys | no | org |
| api-keys revoke | DELETE | /api/v1/organizations/{org}/api-keys/{key} | yes | org, key |
| deals list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/deals | no | org, workspace |
| deals get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/deals/{deal} | no | deal |
| deals create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/deals | no | org, workspace |
| deals update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/deals/{deal} | no | deal |
| deals delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/deals/{deal} | yes | deal |
| deals move | POST | /api/v1/organizations/{org}/workspaces/{workspace}/deals/{deal}/move | no | deal |
| deals forecast | GET | /api/v1/organizations/{org}/workspaces/{workspace}/deal-forecast | no | org, workspace |
| pipelines list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/pipelines | no | org, workspace |
| pipelines get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/pipelines/{pipeline} | no | pipeline |
| companies list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/companies | no | org, workspace |
| companies get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/companies/{company} | no | company |
| companies create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/companies | no | org, workspace |
| companies update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/companies/{company} | no | company |
| companies delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/companies/{company} | yes | company |
| companies duplicates | GET | /api/v1/organizations/{org}/workspaces/{workspace}/companies/{company}/duplicates | no | company |
| companies merge | POST | /api/v1/organizations/{org}/workspaces/{workspace}/companies/merge | yes | org, workspace |
| contacts overview | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contacts/{contact}/overview | no | contact |
| contacts merge | POST | /api/v1/organizations/{org}/workspaces/{workspace}/contacts/merge | yes | org, workspace |
| contact-fields list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/contact-fields | no | org, workspace |
| activities list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/activities | no | org, workspace |
| activities log | POST | /api/v1/organizations/{org}/workspaces/{workspace}/activities | no | org, workspace |
| inbox assign | POST | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/threads/{thread}/assign | no | thread |
| inbox bulk-read | POST | /api/v1/organizations/{org}/workspaces/{workspace}/inbox/threads/bulk-read | no | org, workspace |
| campaigns leads | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/leads | no | campaign |
| learning overview | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/learning/overview | no | campaign |
| learning activity | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/learning/activity | no | campaign |
| learning outcomes | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/learning/outcomes | no | campaign |
| learning graph | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/learning/graph | no | campaign |
| learning auto-mode-state | GET | /api/v1/organizations/{org}/workspaces/{workspace}/campaigns/{campaign}/learning/auto-mode-state | no | campaign |
| learning workspace-overview | GET | /api/v1/organizations/{org}/workspaces/{workspace}/learning/overview | no | org, workspace |
| alerts list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/alerts | no | org, workspace |
| alerts ack | POST | /api/v1/organizations/{org}/workspaces/{workspace}/alerts/{alert}/ack | no | alert |
| alerts resolve | POST | /api/v1/organizations/{org}/workspaces/{workspace}/alerts/{alert}/resolve | no | alert |
| warmup status | GET | /api/v1/organizations/{org}/workspaces/{workspace}/connectors/{connector}/warmup | no | connector |
| email-auth status | GET | /api/v1/organizations/{org}/workspaces/{workspace}/email-auth | no | org, workspace |
| sequences list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/sequence-library | no | org, workspace |
| sequences create | POST | /api/v1/organizations/{org}/workspaces/{workspace}/sequence-library | no | org, workspace |
| sequences update | PATCH | /api/v1/organizations/{org}/workspaces/{workspace}/sequence-library/{template} | no | template |
| sequences delete | DELETE | /api/v1/organizations/{org}/workspaces/{workspace}/sequence-library/{template} | yes | template |
| teams members | GET | /api/v1/organizations/{org}/workspaces/{workspace}/teams/members | no | org, workspace |
| usage get | GET | /api/v1/organizations/{org}/teams/api-usage | no | org |
| dashboard get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/dashboard | no | org, workspace |
| copilot sessions-list | GET | /api/v1/organizations/{org}/workspaces/{workspace}/copilot/sessions | no | org, workspace |
| copilot sessions-get | GET | /api/v1/organizations/{org}/workspaces/{workspace}/copilot/sessions/{session} | no | session |
Platform commands not in the registry above: copilot ask (session-based, see Copilot), auth login|status|logout, api <METHOD> <path>, completion bash|zsh|fish.
Unsupported Surfaces
The CLI intentionally returns unsupported_operation for public surfaces that are not ready yet, including Signals and Webhooks. Do not work around this by calling app-private routes.
Examples for AI Agents
Inspect Campaign Health
firstsales whoami --json
firstsales campaigns get --org org_123 --workspace ws_123 --campaign camp_123 --json
firstsales campaigns progress --org org_123 --workspace ws_123 --campaign camp_123 --json
firstsales campaigns analytics --org org_123 --workspace ws_123 --campaign camp_123 --jsonPause a Campaign After Checking State
firstsales campaigns get --org org_123 --workspace ws_123 --campaign camp_123 --json
firstsales campaigns pause \
--org org_123 \
--workspace ws_123 \
--campaign camp_123 \
--idempotency-key pause-camp-123-2026-06-30 \
--json
firstsales campaigns get --org org_123 --workspace ws_123 --campaign camp_123 --jsonApprove a Draft Safely
firstsales inbox thread --org org_123 --workspace ws_123 --thread thread_123 --json
firstsales inbox approve-draft \
--org org_123 \
--workspace ws_123 \
--email email_123 \
--idempotency-key approve-email-123 \
--jsonRotate an API Key
firstsales api-keys list --org org_123 --json
firstsales api-keys create \
--org org_123 \
--data '{"name":"CI automation","scopes":["campaigns:read","contacts:write"],"accessLevel":"workspace"}' \
--json
firstsales api-keys revoke --org org_123 --key old_key_123 --confirm --jsonTroubleshooting
| Symptom | Check |
| --- | --- |
| missing_api_key | Set FIRSTSALES_API_KEY or pass --api-key. |
| invalid_api_key | Confirm the key was copied correctly and not revoked. |
| insufficient_scope | Create a key with the required resource scope. |
| Workspace ID is required | Pass --workspace for workspace-scoped commands. |
| Workspace API keys cannot access organization management endpoints | Use an organization-level key with explicit org scopes. |
| destructive_confirmation_required | Add --confirm only if the delete/revoke/cancel action is intentional. |
| unsupported_operation | The surface is not part of the public Developer API yet. |
| JSON parse error for --data | Validate the JSON string or use --data-file. |
FAQ
Is this an SDK?
No. It is a thin CLI over the public Developer API. Use the OpenAPI contract to generate SDKs.
Does the CLI store API keys?
The CLI can read local profiles, but automation should prefer environment variables. Do not commit profile files or keys.
Does whoami mutate anything?
No. It calls GET /api/v1/whoami and prints the authenticated identity/context.
Why do deletes require --confirm?
The CLI is designed for AI agents and scripts. Destructive commands need an explicit operator signal.
Can I use app-private routes if a command is missing?
No. Only /api/v1 endpoints are supported. App-private, callback, tracking, unsubscribe, internal, and support routes are intentionally excluded.
Where are the docs?
Developer docs are hosted from firstsalesio/docs and are prepared for developer.firstsales.io.
Development
npm test
node bin/firstsales.js commands --json
npm pack --dry-run --jsonThe command registry is the source for CLI docs sync. When public API routes change, update the registry, tests, docs, and OpenAPI contract together.
