@saleshandy/saleshandy-cli
v0.1.15
Published
Official CLI for SalesHandy Open API
Readme
@saleshandy/saleshandy-cli
Official CLI for the SalesHandy Open API. Manage prospects, sequences, email accounts, tasks, and more from your terminal.
Install
npm install -g @saleshandy/saleshandy-cliRequires Node.js 18 or later.
Quick Start
1. Get your API key
Go to SalesHandy API Keys Settings and generate an API key.
2. Authenticate
saleshandy auth login
# Prompts for your API key interactively
# Or pass it directly:
saleshandy auth login --api-key YOUR_API_KEY3. Run commands
saleshandy prospects list
saleshandy sequences list --json
saleshandy tasks list --limit 5Authentication
Login and profiles
The CLI stores your API key locally at ~/.config/saleshandy/config.json.
# Default profile
saleshandy auth login --api-key YOUR_API_KEY
# Named profile (for multiple accounts)
saleshandy auth login --api-key ANOTHER_KEY --profile client-a
# Use a specific profile for a command
saleshandy prospects list --profile client-a
# Switch default profile
saleshandy auth switch client-a
# See all profiles
saleshandy auth status
# Remove a profile
saleshandy auth logout
saleshandy auth logout --profile client-aEnvironment variable
You can skip login entirely by setting the env var. This is useful for CI/CD:
export SALESHANDY_API_KEY=your_key
saleshandy prospects listPer-command override
saleshandy prospects list --api-key YOUR_KEYPrecedence: --api-key flag > SALESHANDY_API_KEY env var > saved profile.
Output Formats
Every command supports three output formats:
# Table (default) — human-readable
saleshandy prospects list
# JSON — for scripts and piping
saleshandy prospects list --json
# CSV — for spreadsheets
saleshandy prospects list --csvPipe JSON output to jq for filtering:
saleshandy prospects list --json | jq '.[].email'Export to a CSV file:
saleshandy prospects list --csv > contacts.csvDisable colored output:
saleshandy prospects list --no-colorGetting Help
# List all topics
saleshandy --help
# List commands in a topic
saleshandy prospects --help
# See flags, args, and examples for a specific command
saleshandy prospects list --help
saleshandy analytics sequence-stats --helpEvery command has --help. When in doubt, add --help to see exactly what flags and arguments are required.
Common Patterns
Pagination
All list commands support --limit and --page:
saleshandy prospects list --limit 50 --page 1
saleshandy prospects list --limit 50 --page 2Sorting
List commands support --sort (asc/desc) and --sort-by:
saleshandy prospects list --sort desc --sort-by createdAt
saleshandy tasks list --sort-order ASC --sort-by priorityNote: Valid --sort-by values differ per resource. Run <command> --help to see available options.
Passing IDs
Many commands require IDs (sequence IDs, prospect IDs, etc.). IDs in SalesHandy are hashed strings like gOwE5l64wb. You get these from list commands:
# Step 1: List sequences to find the ID
saleshandy sequences list
# Output shows ID column: gOwE5l64wb
# Step 2: Use that ID in another command
saleshandy analytics sequence-stats --sequence-id gOwE5l64wbComma-separated IDs
Some commands accept multiple IDs. Pass them comma-separated:
saleshandy sequences status-update --sequence-ids gOwE5l64wb,aB3xK9mP2w --status pause
saleshandy tasks bulk-skip --task-ids id1,id2,id3JSON body via --file
Import and connect commands accept a JSON file:
saleshandy prospects import --file prospects.json
saleshandy email-accounts connect --file accounts.json
saleshandy enrichment contact --file leads.jsonAsync operations (import, enrichment, connect)
Some operations are async. They return a request ID you can poll:
# Start an import
saleshandy prospects import --file data.json
# Output: ✓ Prospect import has started. Request ID: req_abc123
# Check status
saleshandy prospects import-status req_abc123
# For enrichment, use --wait to poll automatically:
saleshandy enrichment status req_abc123 --waitCommand Reference
auth — Authentication
saleshandy auth login # Interactive login
saleshandy auth login --api-key KEY # Non-interactive
saleshandy auth login --api-key KEY --profile staging
saleshandy auth logout # Remove current profile
saleshandy auth logout --profile staging # Remove named profile
saleshandy auth status # Show all profiles
saleshandy auth switch staging # Switch active profileprospects — Manage Prospects
saleshandy prospects list # List all prospects
saleshandy prospects list --search "[email protected]" # Search by email/name
saleshandy prospects list --limit 50 --page 2 # Paginate
saleshandy prospects list --include-custom-fields # Include custom fields
saleshandy prospects import --file prospects.json # Import from file
saleshandy prospects import-status REQUEST_ID # Check import status
saleshandy prospects verification-status --emails "[email protected],[email protected]"
saleshandy prospects attribute --attribute-id ID --prospect-id ID
# Update prospect status in a sequence
saleshandy prospects status update \
--prospect-id ID --sequence-id ID --step-id ID --status paused
# Status options: replied, finished, paused, unsubscribed, active
# Tags
saleshandy prospects tags list
saleshandy prospects tags list --search "VIP"
saleshandy prospects tags assign --prospects '[{"prospectId":"ID","tagId":"ID"}]'
saleshandy prospects tags unassign --data '[{"prospects":["ID"]}]'sequences — Manage Sequences
saleshandy sequences list # List all
saleshandy sequences list --search "Growth" --limit 10 # Filter
saleshandy sequences status-update --sequence-ids ID1,ID2 --status pause
# Create a sequence (optionally attach email account + schedule in one call)
saleshandy sequences create --title "Q2 Outreach"
saleshandy sequences create --title "Q2 Outreach" --email-account-id EA_ID --schedule-id SCH_ID
# Email accounts on a sequence
saleshandy sequences email-accounts list --sequence-id ID
saleshandy sequences email-accounts add --sequence-id ID --email-account-ids ID1,ID2
saleshandy sequences email-accounts remove --sequence-id ID --email-account-ids ID1
# Import prospects into a sequence
saleshandy sequences prospects-import --file data.json
# Add existing contacts to a sequence step
saleshandy sequences contacts-add --sequence-id ID --step-id ID --contact-ids ID1,ID2
# Steps — list + get + create
saleshandy sequences steps list --sequence-id ID
saleshandy sequences steps get --sequence-id ID --step-id ID
saleshandy sequences steps create \
--sequence-id ID --type 1 --absolute-days 1 --variants-file ./variants.json
# Variants — add + update
saleshandy sequences steps variants create \
--sequence-id ID --step-id ID --type 1 --payload-file ./payload.json
saleshandy sequences steps variants update \
--sequence-id ID --step-id ID --variant-id ID --status 0
saleshandy sequences steps variants update \
--sequence-id ID --step-id ID --variant-id ID --attachment-ids "[]" # clear attachments
# Settings — get + update (codes 1–14, see docs)
saleshandy sequences settings get --sequence-id ID
saleshandy sequences settings get --sequence-id ID --code 6
saleshandy sequences settings update --sequence-id ID --set 6=1 --set 5=1
saleshandy sequences settings update --sequence-id ID --schedule-id SCH_ID
# Priority / distribution
saleshandy sequences priority-distribution update --sequence-id ID --preset 3
# Presets: 1=Prioritise Follow-Ups, 2=Prioritise New Prospects,
# 3=Balanced Sending, 4=Aggressively Prioritise New ProspectsSample variants.json for sequences steps create --type 1 (Email):
[
{
"payload": {
"subject": "Hello {{firstName}}",
"content": "<p>Hi {{firstName}}, quick note.</p>",
"preheader": "Quick note"
},
"attachmentIds": ["aX2vY9wZ1q"]
}
]Sample payload.json for sequences steps variants create --type 2 (LinkedIn Connection Request):
{ "connectionNote": "Hi {{firstName}}, would love to connect." }schedules — Sending schedules
saleshandy schedules list
saleshandy schedules list --json
saleshandy schedules create \
--name "Weekdays 9-5 EST" --timezone America/New_York \
--time-slots-file ./time-slots.json
saleshandy schedules create \
--name "Default" --timezone Asia/Kolkata \
--time-slots-file ./time-slots.json --is-defaultSample time-slots.json (must contain exactly 7 entries):
[
{ "day": 0, "slots": [] },
{ "day": 1, "slots": [{ "start": { "hour": 9, "minute": 0 }, "end": { "hour": 17, "minute": 0 } }] },
{ "day": 2, "slots": [{ "start": { "hour": 9, "minute": 0 }, "end": { "hour": 17, "minute": 0 } }] },
{ "day": 3, "slots": [{ "start": { "hour": 9, "minute": 0 }, "end": { "hour": 17, "minute": 0 } }] },
{ "day": 4, "slots": [{ "start": { "hour": 9, "minute": 0 }, "end": { "hour": 17, "minute": 0 } }] },
{ "day": 5, "slots": [{ "start": { "hour": 9, "minute": 0 }, "end": { "hour": 17, "minute": 0 } }] },
{ "day": 6, "slots": [] }
]attachments — Upload files for email variants
saleshandy attachments upload --file ./proposal.pdf
saleshandy attachments upload --file ./doc.docx --jsonThe returned attachmentId is used in the attachmentIds field of an Email variant payload (see sequences steps create examples above).
email-accounts — Email Accounts
saleshandy email-accounts list # List all
saleshandy email-accounts list --search "gmail" # Filter
saleshandy email-accounts connect --file accounts.json # Connect via SMTP/IMAP
saleshandy email-accounts connect-status REQUEST_ID # Check connection
saleshandy email-accounts reconnect --email-account-ids ID1,ID2
saleshandy email-accounts bulk-update --email-account-ids ID1,ID2 --is-pausedenrichment — Lead Finder
# Enrich contacts
saleshandy enrichment contact --linkedin-urls "https://linkedin.com/in/person"
saleshandy enrichment contact --file contacts.json --reveal-phone
saleshandy enrichment contact --file contacts.json --webhook-url https://example.com/hook
# Enrich companies
saleshandy enrichment company --domains "acme.com,startup.io"
saleshandy enrichment company --file companies.json
# Check status and get results
saleshandy enrichment status REQUEST_ID
saleshandy enrichment status REQUEST_ID --wait # Polls until complete
saleshandy enrichment result REQUEST_ID
# Check credits and rate limits
saleshandy enrichment credits
saleshandy enrichment rate-limitsunified-inbox — Emails
saleshandy unified-inbox unread-count
saleshandy unified-inbox outcomes --limit 10
saleshandy unified-inbox emails list --limit 20 --search "acme"
saleshandy unified-inbox emails list --sentiment positive --start-date 2025-01-01
saleshandy unified-inbox emails thread THREAD_ID
saleshandy unified-inbox emails get THREAD_ID EMAIL_ID
# Reply to an email
saleshandy unified-inbox emails reply \
--thread-id ID --email-id ID \
--to "[email protected]" --content "Thanks for reaching out!"analytics — Reports
# Sequence stats (pass sequence ID from `sequences list`)
saleshandy analytics sequence-stats --sequence-id gOwE5l64wb
# Consolidated stats across multiple sequences
saleshandy analytics consolidated-stats \
--sequence-ids ID1,ID2 --start-date 2025-01-01 --end-date 2025-12-31
# Email account stats
saleshandy analytics email-account-stats --email-id ID
# Team stats
saleshandy analytics team-stats \
--user-ids ID1,ID2 \
--start-date 2025-01-01T00:00:00.000+00:00 \
--end-date 2025-12-31T23:59:59.000+00:00 \
--count-by absolute --type prospect \
--order-by total --limit 10 --page 1tasks — Task Management
saleshandy tasks list # List all tasks
saleshandy tasks list --status overdue --limit 10 # Filter by status
saleshandy tasks list --sequence-id ID # Filter by sequence
saleshandy tasks get TASK_ID # Task details
saleshandy tasks counts # Counts by status
saleshandy tasks assignees # List assignees
# Actions
saleshandy tasks complete TASK_ID
saleshandy tasks skip TASK_ID
saleshandy tasks snooze TASK_ID --snooze-until "2025-12-25T09:00:00.000Z"
saleshandy tasks note-update TASK_ID --note "Called, no answer"
# Bulk actions
saleshandy tasks bulk-skip --task-ids ID1,ID2,ID3
saleshandy tasks bulk-snooze --task-ids ID1,ID2 --snooze-until "2025-12-25T09:00:00.000Z"
saleshandy tasks bulk-status BULK_ACTION_IDdnc — Do Not Contact
saleshandy dnc list # List DNC lists
saleshandy dnc items DNC_LIST_ID # Items in a list
saleshandy dnc add --dnc-list-id ID --items "[email protected],baddomain.com"
saleshandy dnc search --search "bad.com" --type domainfields — Custom Fields
saleshandy fields list --system-fields # Include system fields
saleshandy fields list --no-system-fields # Custom fields onlyclients — Client Management
saleshandy clients list
saleshandy clients list --search "Acme"
saleshandy clients assign --resource-type sequence --client-id ID --resource-ids ID1,ID2
saleshandy clients assign --resource-type emailAccount --client-id ID --resource-ids ID1user — Team Info
saleshandy user team-members
saleshandy user team-members --jsonwarmup — Email Warmup
saleshandy warmup report EMAIL_ACCOUNT_ID 2025-03-15Global Flags
These flags work on every command:
| Flag | Description |
|------|-------------|
| --json | Output as JSON |
| --csv | Output as CSV |
| --profile <name> | Use a named auth profile |
| --api-key <key> | Override API key for this command |
| --no-color | Disable colored output |
| --help | Show help |
Shell Autocomplete
Set up tab completion:
saleshandy autocompleteFollow the printed instructions for your shell (bash/zsh/fish).
FAQ
Q: How do I find the ID I need to pass to a command?
A: Run the list command for that resource first. For example, saleshandy sequences list shows sequence IDs, then use that ID with saleshandy analytics sequence-stats --sequence-id <ID>.
Q: A command says a flag is required but I don't know the value.
A: Run <command> --help to see the description and valid options for each flag. For IDs, list the parent resource first.
Q: How do I pass JSON data?
A: Use --file path/to/file.json for import/connect/enrichment commands. For tag operations, pass inline JSON as a string: --prospects '[{"prospectId":"ID","tagId":"ID"}]'
Q: Can I use this in CI/CD?
A: Yes. Set SALESHANDY_API_KEY as an environment variable and use --json for machine-readable output. Example: SALESHANDY_API_KEY=xxx saleshandy prospects list --json
Q: How do I check the status of an async operation?
A: Import, enrichment, and connect operations return a request ID. Use the corresponding *-status command: saleshandy prospects import-status <requestId> or saleshandy enrichment status <requestId> --wait
Links
License
MIT - see LICENSE
