Audience: developers. API keys need a Pro or Enterprise plan (legacy Pro and Scale plans included) or an AppSumo Tier 5, 6 or 7 license, and they never work during a trial. Support agent: confirm the user's plan grants API access before giving API advice.
TL;DR: API v2 lives at api.cleanlist.ai/api/v2. Authenticate with a clapi_ Bearer key, each call checks one OAuth scope, and paid bulk work uses a signed quote_id from POST /credits/estimate. Every response uses one envelope, and errors follow the error contract. Connecting Claude instead of writing code? Use the Cleanlist MCP.
API v2
Cleanlist API v2 is the REST API at https://api.cleanlist.ai/api/v2. People and company search return credits_charged: 0, saving leads to a list is free, and enrichment costs 1 credit per work email and 10 per direct dial, charged only when found.
This is the current API. All new integrations should target v2. The older Legacy API (v1) at /api/v1/public is still supported but frozen. See API Versions & Migration for how the two relate.
With API v2 you can search for B2B contacts and companies, enrich them through waterfall enrichment, organize them into lead lists, run smart agents, push lists to your CRM or sequencer with sync, and export the results.
It is built to be agent-friendly: every response carries the same envelope, so an LLM agent always knows where to find task_id, freshness and follow-up hints, and paid operations sit behind a signed estimate so an agent can't overspend.
API v2 and the Cleanlist MCP
The Cleanlist MCP is a connector for Claude. It signs in with your Cleanlist account (no API key to paste) and calls API v2 on your behalf. It is available on more plans than API keys: Starter, Pro, Enterprise, the Pro trial and every AppSumo tier. Use the MCP to work in Claude; use API v2 with a clapi_ key from your own code.
Base URLs
| Surface | Base URL | Auth |
|---|---|---|
| API v2 | https://api.cleanlist.ai/api/v2 | clapi_ key or Clerk session JWT |
| API key management | https://api.cleanlist.ai/api/v1/api-keys | Clerk session JWT only |
All requests must use HTTPS.
Authentication
Send your API key as a Bearer token:
Authorization: Bearer clapi_your_api_key_hereCreate a key in the app under Settings → API keys → Create API key. Beyond the token, every endpoint checks one OAuth scope (for example enrich:write to run an enrichment). The scopes granted to your credential are listed by GET /whoami. See Authentication for the 15 scopes and key management.
The response envelope
Every entity-returning endpoint wraps its payload in the same envelope. These fields sit alongside the endpoint's own payload, and any of them may be null:
| Field | Type | Meaning |
|---|---|---|
task_id | string | A handle for chainable follow-ups (for example, enrich a search cohort by task_id) |
timestamp_ms | integer | Server time the response was produced (freshness marker) |
agent_instructions | string | A per-call nudge for agents (credits remaining, truncation, warnings) |
usage | string | A "what to do next" hint, typically on empty or discovery responses |
message | string | A degraded-state explanation when something was skipped |
Clients that ignore unknown keys keep working as fields are added.
The error envelope
Errors raised by an endpoint use the public error envelope:
{
"error": {
"code": "insufficient_credits",
"problem": "This enrich_list call requires 110 credits; organization has 40.",
"fix": "Top up at app.cleanlist.ai/billing, or reduce the scope of the call.",
"retryable": false,
"docs_url": "https://docs.cleanlist.ai/errors/insufficient-credits",
"request_id": "req_4f1c2a9b3d6e7f80",
"estimated_cost_credits": 110,
"available_credits": 40,
"shortfall_credits": 70
}
}The fix text above is returned verbatim by the API and mentions app.cleanlist.ai/billing. That page does not exist: buy credits or change plan on the Plans page at app.cleanlist.ai/plans (opens in a new tab) (Settings → Plans & billing).
Branch on code. Authentication failures (401), plan and trial blocks (403) and rate limits (429) use a shorter generic shape with an uppercase code and a message, for example {"error": {"code": "RATE_LIMITED", "message": "..."}}. See Errors & Rate Limits for both shapes and every code.
Rate limits
| Limit | Window | Applies to |
|---|---|---|
| 60 requests | per minute | per organization, all keys and members combined |
| 30 requests | per minute | per organization, for AppSumo licenses without a paid Cleanlist plan |
| 30 requests | per minute | per clapi_ API key |
| 60 searches | per UTC day | per organization, POST /people/find called with API keys (all keys combined) |
When you exceed a limit you get a 429 with a Retry-After header (seconds) and a RATE_LIMITED error body. See Errors & Rate Limits.
Credits and the quote model
Reads (filters, list reads, status polls, exports, whoami, balance) are free, and so is search itself. Saving leads to a list is also free; enrichment is billed separately. Paid bulk operations (bulk enrichment, by-task enrichment, smart agents, CRM and sequencer sync) require a signed quote:
- Call
POST /credits/estimatewith the operation shape. You get back aquote_id(HMAC-signed, 5-minute TTL, single use) and theestimated_cost. - Pass that
quote_idto the paid endpoint. The server recomputes the cost and rejects the call withspend_cap_exceededif it would exceed the quote.
Sync calls also need approved: true, set only after a person has confirmed the push. See Credits for balances, estimates, usage reporting and the full cost table.
Quick start
A complete flow: confirm a key, estimate a bulk enrichment, run it, then poll for completion.
# 1. Create a key in the app: Settings → API keys → Create API key
# 2. Confirm identity, scopes, and tier
curl https://api.cleanlist.ai/api/v2/whoami \
-H "Authorization: Bearer clapi_your_api_key"
# 3. Estimate a bulk enrichment over an existing list
curl -X POST https://api.cleanlist.ai/api/v2/credits/estimate \
-H "Authorization: Bearer clapi_your_api_key" \
-H "Content-Type: application/json" \
-d '{"tool": "enrich_list", "list_id": "LIST_ID", "scope": "partial"}'
# 4. Run it with the returned quote_id
curl -X POST https://api.cleanlist.ai/api/v2/enrichment/bulk \
-H "Authorization: Bearer clapi_your_api_key" \
-H "Content-Type: application/json" \
-d '{"list_id": "LIST_ID", "scope": "partial", "quote_id": "qte_v1_..."}'
# 5. Poll until terminal
curl https://api.cleanlist.ai/api/v2/enrichment/status/WORKFLOW_ID \
-H "Authorization: Bearer clapi_your_api_key"Prefer code? The same flow is a few typed lines with an official SDK:
workspace.credits_estimate(...) then enrichment.enrich_list(...) then enrichment.enrichment_status(...).
See the SDKs for Python, TypeScript and Java.
Endpoint index
All paths below are relative to https://api.cleanlist.ai/api/v2 unless noted. The Scope column lists the OAuth scope each endpoint checks.
Workspace and identity
| Method | Path | Scope |
|---|---|---|
GET | /whoami | none (any valid credential) |
GET | /credits/balance | credits:read |
POST | /credits/estimate | credits:read |
GET | /api-keys | admin:api_keys |
GET | /usage | admin:api_keys |
Search
| Method | Path | Scope |
|---|---|---|
GET | /people/find/filters | people:read |
POST | /people/find | people:read |
POST | /people/find/compile | people:read |
POST | /people/find-at-companies | people:read |
GET | /people/find-at-companies/status/{task_id} | people:read |
GET | /search/companies/filters | companies:read |
POST | /search/companies | companies:read |
POST | /search/companies/similar | companies:read |
Search costs 0 credits. Full reference: People Finder API and Company Search API.
Lead lists
| Method | Path | Scope |
|---|---|---|
POST | /lead-lists | lists:write |
GET | /lead-lists | lists:read |
GET | /lead-lists/{list_id} | lists:read |
PATCH | /lead-lists/{list_id} | lists:write |
DELETE | /lead-lists/{list_id} | lists:write |
GET | /lead-lists/{list_id}/leads | lists:read |
POST | /lead-lists/{list_id}/leads | lists:write |
DELETE | /lead-lists/{list_id}/leads | lists:write |
POST | /lead-lists/{list_id}/csv-import | lists:write (+ enrich:write if dispatching) |
POST | /lead-lists/{list_id}/find-people | lists:write |
GET | /lead-lists/{list_id}/find-people/status/{workflow_id} | people:read |
Full reference: Lead Lists.
Enrichment
| Method | Path | Scope |
|---|---|---|
POST | /enrichment/person | enrich:write |
POST | /enrichment/company | enrich:write |
POST | /enrichment/by-task | enrich:write |
POST | /enrichment/bulk | enrich:write |
GET | /enrichment/status/{workflow_id} | enrich:read |
Full reference: Enrichment.
Smart agents
| Method | Path | Scope |
|---|---|---|
POST | /smart-agents/run | smart_agents:write |
GET | /smart-agents | smart_agents:read |
GET | /smart-agents/{smart_agent_task_id} | smart_agents:read |
Smart agents run an AI instruction over the leads in a list and write the output into a column. Pricing comes from the quote. Full reference: Smart Agents.
Sync and export
| Method | Path | Scope |
|---|---|---|
POST | /migrate/crm | sync:write |
POST | /migrate/sequencer | sync:write |
POST | /export/csv/signed-url | export:read |
GET | /export/json | export:read |
Sync pushes a list to HubSpot or Salesforce (/migrate/crm) or into a Lemlist campaign (/migrate/sequencer) at 0.2 credits per lead. See CRM & Sequencer Sync and Export.
API key management (Clerk session JWT)
| Method | Path |
|---|---|
POST | /api/v1/api-keys |
GET | /api/v1/api-keys |
POST | /api/v1/api-keys/{key_id}/revoke |
POST | /api/v1/api-keys/revoke-all |
GET | /api/v1/api-keys/{key_id}/requests |
What the OpenAPI spec covers
The served spec at /openapi-public-v2.json lists 30 operations. A few live endpoints are callable but not in it: POST /credits/estimate, the three company search endpoints and the two sync endpoints. They are documented on this site. The Cleanlist MCP also uses some extra v2 routes (folders, moving and filtering leads, personal email, skills, CRM record reads). Those are built for the MCP, are not available to AppSumo-only workspaces, and are not covered in this reference.
whoami
The fastest way to confirm a credential works and see what it can do:
curl https://api.cleanlist.ai/api/v2/whoami \
-H "Authorization: Bearer clapi_your_api_key"{
"user_email": "y***@yourcompany.com",
"user_id": "user_2abc...",
"user_name": "Your Name",
"organization_id": "org_2xyz...",
"organization_name": "Your Company",
"auth_type": "api_key",
"scopes": ["people:read", "companies:read", "lists:read", "lists:write", "enrich:read", "enrich:write", "credits:read"],
"tier": "pro",
"appsumo_tier": null,
"features": ["api_access", "data_source_csv_upload"],
"timestamp_ms": 1717430400000
}tier is one of free, starter, pro or enterprise (the legacy Scale plan reads enterprise). appsumo_tier is 1 to 7 for AppSumo workspaces, else null. For api_key auth, user_email is masked so a leaked key can't reveal the creator's full address.
Learn more
- Quickstart · SDKs (Python · TypeScript · Java)
- Authentication & scopes
- Credits & the quote model
- People Finder API · Company Search API
- Enrichment endpoints · Enrichment types & pricing
- Lead lists · Smart agents
- CRM & Sequencer Sync · Export
- Errors & rate limits · Polling & async results
- OpenAPI spec
- Connect Cleanlist to Claude (MCP)