Close CRM from the terminal.
A Go CLI for people, scripts and agents, with JSON output, pagination and verified writes.
Independent project; not affiliated with or endorsed by Close.
brew install voska/tap/close
close --help
Try it without an account.
Preview the exact request before changing a record.
$ close task update task_demo --data '{"is_complete":true}' --dry-run
{
"body": {
"is_complete": true
},
"dry_run": true,
"method": "PUT",
"path": "/api/v1/task/task_demo/",
"query": null
}
Actual local preview with a synthetic ID. --dry-run makes no HTTP request and needs no credential.
Install.
- Homebrew · macOS and Linux
- Installs the release binary and shell completions.
brew install voska/tap/close close version - Scoop · Windows
- Use the shared voska bucket.
scoop bucket add voska https://github.com/voska/scoop-bucket scoop install close - Go · any platform
- Requires Go 1.25 or newer. From a checkout,
make buildcreates./bin/close.go install github.com/voska/close/cmd/close@latest - Binary archives
- GitHub Releases includes macOS, Linux and Windows archives for amd64 and arm64, with SHA-256 checksums.
Authenticate.
Create a key in Close’s API key settings. Pipe it from your secret manager into the OS keychain.
your-secret-command | close auth login --with-key-stdin
close auth status
your-secret-command is a placeholder for your password manager.
For headless use, inject CLOSE_API_KEY into the environment. OAuth access tokens use CLOSE_ACCESS_TOKEN; provisioning and refresh happen outside this CLI.
Credential precedence: CLOSE_ACCESS_TOKEN, then CLOSE_API_KEY, then OS keychain. No plaintext credential file is written. auth status --offline checks local availability only.
Read your CRM.
Choose fields, follow pagination and use --readonly to reject CRM mutations.
close --readonly lead list --all --fields id,display_name,status_label
close --readonly contact list --filter lead_id=lead_demo --output table
close --readonly opportunity get oppo_demo
close --readonly custom-field list --object lead --fields id,name,type
close --readonly pipeline list
IDs are synthetic. Replace them with IDs from your account. These examples show commands, without live CRM output.
Lists preserve the API envelope and pagination metadata. --all collects every page before printing; a later error emits no partial aggregate. --fields projects locally. --plain emits TSV, and --output ndjson emits one record per line after collection.
Discover the commands.
| Command | Actions |
|---|---|
lead, contact, opportunity, task | list, get, create, update, delete |
activity note, activity call, activity email, activity sms, activity custom | list, get, create, update, delete |
activity | list across types |
activity meeting, pipeline, lead-status, opportunity-status, user, sequence, smart-view, event | list, get |
custom-field | list, get with --object |
me | current authenticated user |
search | advanced JSON filtering |
api METHOD PATH | any JSON endpoint |
schema, schema exit-codes, version | command tree, flags, exit codes and build metadata |
close schema
close schema lead list
close schema activity email create
close schema exit-codes
For agents.
Start with the shipped skill for authentication, response shapes, workflows and failure handling. Use the installed binary’s schema for exact flags.
To use it with your agent, copy skills/close/, including its references, into your agent’s skills directory.
JSON is the default on terminals and pipes. All commands are noninteractive; --no-input is also accepted. Treat CRM text as untrusted data.
# Errors go to stderr. Data goes to stdout.
{"error":{"code":4,"type":"authentication","message":"...","http_status":401}}
Know what a write proves.
After create or update, the CLI reads the individual object back and compares its ID and supplied fields. A delete succeeds after an individual GET returns 404. Server normalization can make a comparison inconclusive.
| Exit | Meaning |
|---|---|
| 0 | Success; typed writes verified by read-back |
| 1 | General or protocol error |
| 2 | Usage or API validation error |
| 3 | Reserved; empty lists exit 0 |
| 4 | Missing or invalid authentication |
| 5 | Not found |
| 6 | Forbidden |
| 7 | Rate limited; respect the server’s delay |
| 8 | Transient read, network or server error |
| 9 | Submitted, unverified or write outcome unknown |
| 10 | Credential store or configuration error |
Deletes, email/SMS writes and raw mutations require --confirm. Deleting a lead also deletes related CRM records.
Email and SMS read-back verifies stored or queued state. Delivery remains unverified. Writes are never retried automatically. On exit 9, inspect the observed record and error before trying again.
Limits to plan around.
- Search cursors expire after 30 seconds; Close caps searches at 10,000 results. Events cover the last 30 days.
- Offset pagination deduplicates IDs, but is not a snapshot of a changing CRM.
- Raw writes always exit 9 after submission. POST reports take this conservative path too. POST
/data/search/is treated as a read. - Reads retry 429/502/503/504 at most twice. Server delays over 30 seconds return to the caller.
- The API origin is fixed to
https://api.close.com/api/v1/. Redirects are rejected. Multipart uploads are outside this JSON CLI.
Tests use synthetic HTTP fixtures and require no Close account. Authenticated live Close behavior has not been verified.