Documentation
Copper CLI
copper-pp-cli
Install
npx -y @mvanhorn/printing-press-library install copperInstalls the CLI binary and the agent skill for Claude Code, Codex, Cursor, Gemini CLI, Copilot, and more. Add --cli-only or --skill-only for one half. Requires Node.
Documentation
The Copper CRM command line no one else built: full CRUD plus a local database, weighted pipeline forecasting, stale-deal detection, and the bulk operations Copper's own API refuses to provide.
Copper has no CLI, no Go client, and no agent-native tool. This turns a click-heavy web CRM into a scriptable, offline-queryable surface. It mirrors people, companies, leads, opportunities, projects, tasks, and activities into local SQLite, then adds the weighted forecast (forecast), cold-deal sweep (stale), and rate-limit-aware bulk editor (bulk) that the API and web UI leave out.
Authentication
Copper uses a multi-header API key. Set COPPER_API_KEY (System Settings -> API Keys -> Create a Key) and COPPER_USER_EMAIL (the email of the key owner). Every request sends X-PW-AccessToken, X-PW-UserEmail, and X-PW-Application: developer_api.
Quick Start
# Verify both credentials are wired before any live call
copper-pp-cli doctor --dry-run
# Mirror the pipeline graph into local SQLite
copper-pp-cli sync --resources opportunities,pipelines,pipeline_stages,users
# Weighted expected revenue, grouped by stage
copper-pp-cli forecast --by stage --agent
# Find open deals gone cold for 3+ weeks
copper-pp-cli stale --days 21 --agent
Unique Features
These capabilities aren't available in any other tool for this API.
Pipeline intelligence
-
forecast— Weighted expected-revenue roll-up: sums monetary_value x win_probability over open opportunities, grouped by stage, assignee, or close-month.Reach for this instead of exporting CSV and pivoting by hand for any expected-revenue or commit/quota question.
copper-pp-cli forecast --pipeline 12345 --by stage --agent -
stale— Surfaces open opportunities with no interaction in N days, sorted by staleness x value, across all reps.Use to find deals going cold before they die; pipe the output into bulk reassign.
copper-pp-cli stale --days 21 --by assignee --agent -
who— Joins an opportunity to its company, people, and recent activities into one related-records view.Use for one-call deal prep before nudging or logging a touch.
copper-pp-cli who opportunity:88 --agent
Operations Copper's API refuses to provide
-
bulk— Applies field updates (stage, owner, custom fields) across many opportunities with bounded concurrency and heuristic 429 backoff.Use for mass updates to existing records; the safe way to avoid the rate-limit wall a naive loop hits.
copper-pp-cli bulk move --query stale.json --set pipeline_stage_id=9 --concurrency 4 --dry-run -
upsert— Match-then-create-or-update for people and leads; normalizes the people.emails[] vs leads.email shape difference.Use to sync external rows without creating duplicates; not a blind create.
copper-pp-cli upsert person --match email --file contacts.json --dry-run -
dedupe— Local SQLite self-join surfacing people or leads that share an email, name, or company.Run before or after a sync to catch duplicate contacts the API will not flag.
copper-pp-cli dedupe people --on email --agent
CRM hygiene
-
log— Creates an activity with the type resolved by name (bumps interaction_count); log fix deletes and recreates to edit an immutable activity.Use to log or correct a single touch; for the same touch across many records use bulk.
copper-pp-cli log call --on opportunity:88 --note "Left voicemail"
Recipes
Monday weighted forecast by rep
copper-pp-cli forecast --by assignee --agent --select assignee_name,weighted_value,open_value
Commit view per rep without a spreadsheet pivot.
Sweep then bulk-reassign cold deals
copper-pp-cli stale --days 30 --by assignee --agent
List cold deals grouped by owner. Save the JSON, then feed the ids into the bulk reassign command (with --set assignee_id=) to mass-reassign — preview with --dry-run before applying.
Idempotent contact import
copper-pp-cli upsert person --match email --file leads.json --dry-run
Create-or-update external rows without duplicating contacts.
One-call deal prep
copper-pp-cli who opportunity:88 --agent --select company.name,people.name,activities.details
Pull the deal's company, contacts, and recent touches in one narrowed view.
Usage
Run copper-pp-cli --help for the full command reference and flag list.
Paths & environment variables
This CLI separates local files into four path kinds:
| Kind | Contents |
|---|---|
config | User-editable settings such as config.toml and saved profiles |
data | Durable local data: credentials.toml, data.db, cookies, browser-session proof files, and other auth sidecars |
state | Runtime state such as persisted queries, jobs, and teach.log |
cache | Regenerable HTTP/cache files |
Each kind resolves independently. The ladder is:
- Per-kind env var:
COPPER_CONFIG_DIR,COPPER_DATA_DIR,COPPER_STATE_DIR, orCOPPER_CACHE_DIR --home <dir>for this invocationCOPPER_HOMEfor a flat relocated root- XDG env vars:
XDG_CONFIG_HOME,XDG_DATA_HOME,XDG_STATE_HOME,XDG_CACHE_HOME - Platform defaults matching existing installs
For containers and agent sandboxes, prefer a single relocated root:
export COPPER_HOME=/srv/copper
copper-pp-cli doctor
Under COPPER_HOME=/srv/copper, the four dirs resolve to /srv/copper/config, /srv/copper/data, /srv/copper/state, and /srv/copper/cache.
MCP servers do not receive CLI flags from the host. Put relocation in the host env block:
{
"mcpServers": {
"copper": {
"command": "copper-pp-mcp",
"env": {
"COPPER_HOME": "/srv/copper"
}
}
}
}
Precedence matters in fleets: an ambient per-kind variable such as COPPER_DATA_DIR overrides an explicit --home for that kind. Use COPPER_HOME or the per-kind variables for durable fleet relocation; treat --home as the weaker per-invocation lever.
Relocation is one-way. Unsetting COPPER_HOME does not move files back to platform defaults, and doctor cannot find credentials left under a former root. Move the files manually before unsetting relocation variables.
Existing installs keep working because the platform-default rung matches the legacy layout. On the first auth write, stored secrets leave config.toml and are consolidated into credentials.toml under the data directory. Run copper-pp-cli doctor --fail-on warn to check path and credential-location warnings in automation.
Commands
account
Account details
copper-pp-cli account- Fetch account details
activities
Manage activities (notes and logged interactions)
copper-pp-cli activities create- Create a new activitycopper-pp-cli activities delete- Delete an activitycopper-pp-cli activities get- Fetch an activity by idcopper-pp-cli activities search- List/search activities
activity-types
Activity types
copper-pp-cli activity-types- List all activity types
companies
Manage companies
copper-pp-cli companies activities- List a company's activitiescopper-pp-cli companies create- Create a new companycopper-pp-cli companies delete- Delete a companycopper-pp-cli companies get- Fetch a company by idcopper-pp-cli companies search- List/search companiescopper-pp-cli companies update- Update a company
contact-types
Contact types
copper-pp-cli contact-types- List all contact types
custom-activity-types
Custom activity types
copper-pp-cli custom-activity-types create- Create a new custom activity typecopper-pp-cli custom-activity-types get- Fetch a custom activity type by idcopper-pp-cli custom-activity-types list- List all custom activity typescopper-pp-cli custom-activity-types update- Update a custom activity type
custom-field-definitions
Custom field definitions
copper-pp-cli custom-field-definitions create- Create a new custom field definitioncopper-pp-cli custom-field-definitions delete- Delete a custom field definitioncopper-pp-cli custom-field-definitions get- Fetch a custom field definition by idcopper-pp-cli custom-field-definitions list- List all custom field definitionscopper-pp-cli custom-field-definitions update- Update a custom field definition
customer-sources
Customer (lead) sources
copper-pp-cli customer-sources- List all customer sources
lead-statuses
Lead statuses
copper-pp-cli lead-statuses- List all lead statuses
leads
Manage leads
copper-pp-cli leads activities- List a lead's activitiescopper-pp-cli leads convert- Convert a lead into a person/company/opportunitycopper-pp-cli leads create- Create a new leadcopper-pp-cli leads delete- Delete a leadcopper-pp-cli leads get- Fetch a lead by idcopper-pp-cli leads search- List/search leadscopper-pp-cli leads update- Update a leadcopper-pp-cli leads upsert- Create or update a lead, matched by email or a custom field
loss-reasons
Opportunity loss reasons
copper-pp-cli loss-reasons- List all loss reasons
opportunities
Manage opportunities (deals)
copper-pp-cli opportunities create- Create a new opportunitycopper-pp-cli opportunities delete- Delete an opportunitycopper-pp-cli opportunities get- Fetch an opportunity by idcopper-pp-cli opportunities search- List/search opportunitiescopper-pp-cli opportunities update- Update an opportunity
people
Manage people (contacts)
copper-pp-cli people activities- List a person's activitiescopper-pp-cli people create- Create a new personcopper-pp-cli people delete- Delete a personcopper-pp-cli people fetch-by-email- Fetch a person by email addresscopper-pp-cli people get- Fetch a person by idcopper-pp-cli people search- List/search peoplecopper-pp-cli people update- Update a person
pipeline-stages
Pipeline stages
copper-pp-cli pipeline-stages- List all pipeline stages
pipelines
Sales pipelines
copper-pp-cli pipelines list- List all pipelinescopper-pp-cli pipelines stages- List stages within a specific pipeline
projects
Manage projects
copper-pp-cli projects create- Create a new projectcopper-pp-cli projects delete- Delete a projectcopper-pp-cli projects get- Fetch a project by idcopper-pp-cli projects search- List/search projectscopper-pp-cli projects update- Update a project
tags
Tags used across records
copper-pp-cli tags- List all tags
tasks
Manage tasks
copper-pp-cli tasks create- Create a new taskcopper-pp-cli tasks delete- Delete a taskcopper-pp-cli tasks get- Fetch a task by idcopper-pp-cli tasks search- List/search taskscopper-pp-cli tasks update- Update a task
users
Users in the account
copper-pp-cli users get- Fetch a user by idcopper-pp-cli users search- List/search users
webhooks
Webhook subscriptions
copper-pp-cli webhooks create- Create a new webhook subscriptioncopper-pp-cli webhooks delete- Delete (unsubscribe) a webhook subscriptioncopper-pp-cli webhooks get- Fetch a webhook subscription by idcopper-pp-cli webhooks list- List all webhook subscriptions
Output Formats
# Human-readable table (default in terminal, JSON when piped)
copper-pp-cli account
# JSON for scripting and agents
copper-pp-cli account --json
# Filter to specific fields
copper-pp-cli account --json --select id,name,status
# Dry run — show the request without sending
copper-pp-cli account --dry-run
# Agent mode — JSON + compact + no prompts in one flag
copper-pp-cli account --agent
Agent Usage
This CLI is designed for AI agent consumption:
- Non-interactive - never prompts, every input is a flag
- Pipeable -
--jsonoutput to stdout, errors to stderr - Filterable -
--select id,namereturns only fields you need - Previewable -
--dry-runshows the request without sending - Explicit retries - add
--idempotentto create retries and--ignore-missingto delete retries when a no-op success is acceptable - Confirmable -
--yesfor explicit confirmation of destructive actions - Piped input - write commands can accept structured input when their help lists
--stdin - Offline-friendly - sync/search commands can use the local SQLite store when available
- Agent-safe by default - no colors or formatting unless
--human-friendlyis set
Exit codes: 0 success, 2 usage error, 3 not found, 4 auth error, 5 API error, 7 rate limited, 10 config error.
Health Check
copper-pp-cli doctor
Verifies configuration, credentials, and connectivity to the API.
Configuration
Run copper-pp-cli doctor to see the resolved config, data, state, and cache directories. The platform-default config path is ``; --home, COPPER_HOME, and per-kind env vars can relocate it.
Static request headers can be configured under headers; per-command header overrides take precedence.
Environment variables:
| Name | Kind | Required | Description |
|---|---|---|---|
COPPER_API_KEY | per_call | Yes | Set to your API credential. |
agentcookie (optional)
If you use agentcookie to sync secrets across machines, this CLI auto-adopts agentcookie-managed credentials with no extra setup. When the daemon writes to this CLI's config, copper-pp-cli doctor reports agentcookie: detected and auth-status labels the source as agentcookie. Skip this section if you don't use agentcookie - the CLI works the same as any other.
Troubleshooting
Authentication errors (exit code 4)
- Run
copper-pp-cli doctorto check credentials - Verify the environment variable is set:
echo $COPPER_API_KEYNot found errors (exit code 3) - Check the resource ID is correct
- Run the
listcommand to see available items
API-specific
- 401 authentication error — Set both COPPER_API_KEY and COPPER_USER_EMAIL; the email must be the key owner's account email
- 429 Too Many Requests on a bulk run — Lower --concurrency (Copper caps near 180 req/min and sends no rate-limit headers)
- forecast or stale returns nothing — Run sync --resources opportunities first; these commands read the local mirror
Sources & Inspiration
This CLI was built by studying these projects and resources:
- salespreso/prospyr — Python (7 stars)
- Gamesight/copper-typescript — TypeScript (6 stars)
- ClaimerApp/copper-sdk — Python (5 stars)
- dazanza/copper-mcp — JavaScript
Generated by CLI Printing Press
For agents: pass /documentation/copper/agents.md to install this CLI from a prompt.