npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@firstsales.io/cli

v0.1.2

Published

Command-line interface for the FirstSales Developer API.

Downloads

404

Readme

@firstsales.io/cli

Control FirstSales from Codex, Claude Code, Gemini, Claude.ai, CI, scripts, and your terminal.

Version Node CLI Developer API License

"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/cli

Package page:

https://www.npmjs.com/package/@firstsales.io/cli

Source repository:

https://github.com/firstsalesio/firstsales-cli

Configure

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" \
  --json

Verify Identity

firstsales whoami --json

whoami 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 --pretty

First Read

firstsales orgs list --json
firstsales workspaces list --org org_123 --json
firstsales campaigns list --org org_123 --workspace ws_123 --json

First Safe Mutation

firstsales contacts create \
  --org org_123 \
  --workspace ws_123 \
  --data '{"email":"[email protected]","firstName":"Alex"}' \
  --idempotency-key import-row-001 \
  --json

Destructive Mutation

firstsales contacts delete \
  --org org_123 \
  --workspace ws_123 \
  --contact contact_123 \
  --confirm \
  --json

Configuration

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

  1. --api-key
  2. FIRSTSALES_API_KEY
  3. selected local profile

Base URL Resolution Order

  1. --base-url
  2. FIRSTSALES_BASE_URL
  3. selected local profile
  4. 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 prod

Use --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.fish

API 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"}' --json

Safety 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 --json

Use 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 --confirm

Use 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 --json

Use 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 --json

Posts 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 --json

Use 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 --json

Use 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 --json

Use 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 --json

Use 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"}' --json

Use 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 --json

Use 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 --json

Pause 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 --json

Approve 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 \
  --json

Rotate 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 --json

Troubleshooting

| 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 --json

The command registry is the source for CLI docs sync. When public API routes change, update the registry, tests, docs, and OpenAPI contract together.