Product Updates7 min read

Manage FoxReach from Your Terminal with the CLI

List leads, create campaigns, check analytics, manage webhooks, and more - all from the command line with the official FoxReach CLI.

Osama Ishtiaq
Osama Ishtiaq

Outbound Engineering & CRM Automation

Share
Manage FoxReach from Your Terminal with the CLI

Overview

The FoxReach CLI brings your outreach workspace to the terminal. Built on top of the Python SDK, it gives you fast, scriptable access to leads, campaigns, sequences, templates, email accounts, inbox, analytics, and webhooks - with rich table output by default and a --json flag for piping into other tools. It is one of the official clients listed on the integrations page, alongside the Python and TypeScript SDKs, the n8n node, and the hosted MCP server.

Install it with pip (Python 3.9 or newer):

pip install foxreach-cli

The current release on PyPI is 0.2.0. It depends on the foxreach Python package, so installing the CLI also installs the SDK.

Setup

The CLI authenticates with a workspace API key. Keys start with otr_ and are created in the dashboard under Settings > Integrations > API Keys; the API keys and webhooks guide walks through creating one with the right scopes. A key that only needs to read (reports, exports) can be created with the read scope alone; anything that creates leads or starts campaigns needs write as well.

After installing, save your key:

foxreach config set-key
# API Key: (paste your otr_ key, input is hidden)
# API key saved.

The key is written to ~/.foxreach/config.json. The CLI refuses a key that does not start with otr_.

You can also use environment variables (they take precedence over the config file):

export FOXREACH_API_KEY="otr_your_key"
export FOXREACH_BASE_URL="https://api.foxreach.io/api/v1"  # optional

Verify the setup:

foxreach config show
# API Key:  otr_****...4f2a  (config file)
# Base URL: default

"Default" means https://api.foxreach.io/api/v1, the base of the public v1 API. You only need FOXREACH_BASE_URL or foxreach config set-url when pointing the CLI at a different host. Every request the CLI makes sends the key in the X-API-Key header and is scoped to the workspace that key belongs to.

Leads

# List active leads
foxreach leads list --status active

# Search for leads
foxreach leads list --search "techcorp"

# Get a specific lead
foxreach leads get cld_abc123

# Create a lead
foxreach leads create \
 --email jane@example.com \
 --first-name Jane \
 --last-name Smith \
 --company TechCorp

# Update a lead
foxreach leads update cld_abc123 --company "TechCorp Inc."

# Delete a lead
foxreach leads delete cld_abc123

# See every email sent to a lead and the campaigns it is in
foxreach leads activity cld_abc123

leads list accepts --status with one of active, bounced, unsubscribed, or replied, plus --page and --limit (default 50) for paging. leads create and leads update also take --title, --phone, --linkedin, --website, and --notes. Deleting a lead asks for confirmation first.

Campaigns

# List campaigns
foxreach campaigns list
foxreach campaigns list --status active

# Create a campaign
foxreach campaigns create \
 --name "Q1 Enterprise Outreach" \
 --timezone "America/New_York" \
 --daily-limit 50 \
 --start-hour 9 \
 --end-hour 17

# Add leads to a campaign
foxreach campaigns add-leads cmp_xyz \
 --lead-ids cld_abc123,cld_def456

# Assign email accounts
foxreach campaigns add-accounts cmp_xyz \
 --account-ids acc_sender1

# Start, pause, resume, or check a campaign
foxreach campaigns start cmp_xyz
foxreach campaigns pause cmp_xyz
foxreach campaigns resume cmp_xyz
foxreach campaigns get cmp_xyz

# Change the sending window later
foxreach campaigns update cmp_xyz --daily-limit 100

# Take a lead or an account back out
foxreach campaigns remove-lead cmp_xyz cld_abc123
foxreach campaigns remove-account cmp_xyz acc_sender1

--status on campaigns list filters by draft, active, paused, or completed. pause stops sending while keeping every lead's position in the sequence; resume picks up where it left off.

Sequences

# List sequence steps in a campaign
foxreach sequences list --campaign cmp_xyz

# Add a sequence step
foxreach sequences create --campaign cmp_xyz \
 --subject "Quick question about {{company}}" \
 --body "Hi {{firstName}}, I noticed {{company}} is growing..." \
 --delay-days 0

# Add a follow-up
foxreach sequences create --campaign cmp_xyz \
 --subject "Re: Quick question" \
 --body "Hi {{firstName}}, just following up..." \
 --delay-days 3

# Edit or remove a step
foxreach sequences update --campaign cmp_xyz --sequence seq_1 --delay-days 5
foxreach sequences delete --campaign cmp_xyz --sequence seq_1

--body is required and --subject is optional; a follow-up without a subject is sent in the same thread. --delay-days defaults to 1 if you leave it out, and --step lets you set the step number explicitly.

Templates

# List templates
foxreach templates list

# Get one
foxreach templates get tpl_abc

# Create a template
foxreach templates create \
 --name "SaaS Founder Outreach v1" \
 --subject "Quick question about {{company}}" \
 --body "Hi {{firstName}}..."

# Update a template
foxreach templates update tpl_abc --name "SaaS Founder Outreach v2"

# Delete a template
foxreach templates delete tpl_abc

Email Accounts

foxreach accounts list
foxreach accounts get acc_abc123
foxreach accounts delete acc_abc123

The list shows each account's daily limit, how many emails it has sent today, and its health score, which is handy for a quick check before you assign accounts to a new campaign. Connecting a new account still happens in the dashboard.

Inbox

# List inbox threads
foxreach inbox list
foxreach inbox list --unread --category interested
foxreach inbox list --campaign cmp_xyz --search "pricing"

# Read one thread, or the whole back-and-forth with that lead
foxreach inbox get rpl_abc123
foxreach inbox conversation rpl_abc123

# Mark it, categorize it, star it
foxreach inbox update rpl_abc123 --read --category qualified
foxreach inbox update rpl_abc123 --starred

# Reply from the account that sent the original email
foxreach inbox reply rpl_abc123 --body "Thanks Jane, does Thursday at 10am work?"

# Counts by category
foxreach inbox stats

inbox reply sends through the same email account and thread the lead answered, so the reply lands in their existing conversation. --subject overrides the subject line if you need to. inbox stats prints totals for unread, interested, not interested, out of office, and uncategorized replies.

Analytics

foxreach analytics overview
foxreach analytics campaign cmp_xyz

overview reports workspace-wide totals (accounts, campaigns, leads, sent, replies, reply rate); campaign reports sent, delivered, bounced, replied, and opened counts for one campaign, with a per-day breakdown.

Webhooks

The CLI can subscribe a URL to FoxReach events, the same way the n8n trigger node and the Zapier and Make apps do behind the scenes.

# See the event types you can subscribe to
foxreach webhooks events

# Create a webhook
foxreach webhooks create \
 --url https://example.com/hooks/foxreach \
 --events reply.received,reply.categorized,email.bounced
# Webhook created: whk_abc123
#   Secret: (shown once)
#   (Save this secret - it won't be shown again)

# List, pause, edit, delete
foxreach webhooks list
foxreach webhooks update whk_abc123 --inactive
foxreach webhooks update whk_abc123 --events reply.received --active
foxreach webhooks delete whk_abc123

The secret is printed once on creation and never again. Use it to verify the X-Webhook-Signature header on every delivery (an HMAC-SHA256 hex digest of the raw request body); the API keys and webhooks guide has a worked example. webhooks list shows each webhook's consecutive failure count, which is the first place to look when events stop arriving.

JSON Output for Scripting

Every list, get, and create command supports --json for machine-readable output. List commands print an object with data and meta keys (the same envelope the API returns); get and create commands print the object itself. Pipe it into jq for powerful scripting:

# Get all active lead emails on the first page
foxreach leads list --status active --json | jq -r '.data[].email'

# Count leads per company
foxreach leads list --limit 100 --json | jq -r '.data[].company' | sort | uniq -c | sort -rn

# Export campaign stats
foxreach analytics campaign cmp_xyz --json > campaign_report.json

# Grab the ID of something you just created
foxreach leads create --email jane@example.com --json | jq -r '.id'

meta carries page, page_size, total, and total_pages, so a loop over --page can walk a large list. Commands that mutate without returning an object (start, pause, delete) print a one-line confirmation instead.

Errors and Rate Limits

When the API rejects a request, the CLI prints Error: followed by the API's message to stderr and exits with status 1, so a failed step stops a shell script running under set -e. A missing or revoked key is a 401; a key without the scope the command needs is a 403.

The v1 API allows 100 requests per minute per key. The SDK underneath the CLI retries a 429 response up to three times, sleeping for the number of seconds in the Retry-After header between attempts, so short bursts recover on their own. A loop that creates thousands of leads should still pace itself.

Complete Workflow: Create and Launch a Campaign

Here's a full workflow from the terminal:

# 1. Create leads and capture their IDs
LEAD_1=$(foxreach leads create --email sarah@techcorp.io --first-name Sarah --last-name Chen --company TechCorp --json | jq -r '.id')
LEAD_2=$(foxreach leads create --email mike@startupco.com --first-name Mike --last-name Johnson --company StartupCo --json | jq -r '.id')

# 2. Create campaign
CAMPAIGN_ID=$(foxreach campaigns create --name "Q1 Outreach" --daily-limit 50 --json | jq -r '.id')

# 3. Add sequences
foxreach sequences create --campaign $CAMPAIGN_ID --subject "Quick question" --body "Hi {{firstName}}..." --delay-days 0
foxreach sequences create --campaign $CAMPAIGN_ID --subject "Following up" --body "Hi {{firstName}}, just checking in..." --delay-days 3

# 4. Add leads and accounts
foxreach campaigns add-leads $CAMPAIGN_ID --lead-ids $LEAD_1,$LEAD_2
foxreach campaigns add-accounts $CAMPAIGN_ID --account-ids acc_sender1

# 5. Launch
foxreach campaigns start $CAMPAIGN_ID

# 6. A few days later: who replied?
foxreach inbox list --campaign $CAMPAIGN_ID --category interested

Resources

For Agents

The complete guide to cold email for AI agents

Architectures, framework decision matrix, pattern library, and a 10-minute getting-started path. Free, no signup.

Was this article helpful?

Your feedback helps us improve what we write.

Frequently asked questions

Run pip install foxreach-cli on Python 3.9 or newer. The package installs a foxreach command that wraps the official Python SDK, so the SDK is pulled in automatically. Then run foxreach config set-key and paste an API key that starts with otr_.

Topics

CLIdeveloper toolsPythonautomationproductivity
Osama Ishtiaq

Written by

Osama Ishtiaq

Outbound Engineering & CRM Automation

Osama works on the CRM and integration side of outbound. He writes about AI SDR stacks, workflow automation, and the glue that keeps agents in sync with the systems of record.

View all articles by Osama

Stay ahead of the inbox

Cold email patterns for AI agents, deliverability updates, and product releases.

Browse more posts