New: API Reference docs are live — integrate Cleanlist enrichment into your apps. View API docs →
MCP API
Introduction

TL;DR: The Cleanlist Public API is an agent- and MCP-friendly surface at api.cleanlist.ai/api/v1/public. Authenticate with a clapi_ Bearer token, each call requires an OAuth scope, and paid bulk operations use a signed quote_id from POST /credits/estimate. Every response uses a consistent envelope; every error uses a single error contract.

MCP API

Two public APIs, same base path. Cleanlist exposes two APIs under /api/v1/public: this MCP API (the newer, expanded ~30-endpoint surface documented here, built for agents and integrations) and the older legacy Public API (5 endpoints — validate-key, enrich/bulk, enrich/status, webhooks/deliveries, credits/balance — including webhook delivery). Both are live; use whichever fits your integration.

The Cleanlist MCP API lets you search for B2B contacts and companies, enrich them through waterfall enrichment, organize them into lead lists, run AI smart agents, and push results into your CRM or sequencer — all programmatically.

It was designed to be agent- and MCP-friendly: every response carries a consistent envelope so an LLM agent always knows where to find task_id, freshness, and follow-up hints, and paid operations are gated behind a signed estimate so an agent can't accidentally overspend.

Base URLs

SurfaceBase URLAuth
Public APIhttps://api.cleanlist.ai/api/v1/publicclapi_ key or Clerk JWT
API key managementhttps://api.cleanlist.ai/api/v1/api-keysClerk JWT only

All requests must use HTTPS.

Authentication

Send your API key as a Bearer token:

Authorization: Bearer clapi_your_api_key_here

Beyond the token, every endpoint requires a specific OAuth scope (for example enrich:write to run an enrichment). The scopes granted to your credential are visible via GET /whoami. See Authentication for the full scope model and how to generate keys.

The response envelope

Every entity-returning endpoint wraps its payload in a consistent envelope. These fields are additive — they sit alongside the endpoint's own payload, and any may be null:

FieldTypeMeaning
task_idstringA handle for chainable follow-ups (e.g. enrich a search cohort by task_id)
timestamp_msintegerServer time the response was produced (freshness marker)
agent_instructionsstringA per-call nudge for agents (credits remaining, truncation, warnings)
usagestringA "what to do next" hint, typically on empty/discovery responses
messagestringA degraded-state explanation when something was skipped

Clients that ignore unknown keys keep working as fields are added.

The error envelope

Every error under /api/v1/public/* follows one shape:

{
  "error": {
    "code": "insufficient_credits",
    "problem": "This enrich_list call requires 110 credits; organization has 40.",
    "cause": null,
    "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
  }
}

Parse code to decide behavior; docs_url deep-links to the matching error page. See Errors & Rate Limits for the full code table.

Rate limits

LimitWindowApplies to
60 requests / minuteper organizationall keys and members combined
30 requests / minuteper API keyeach individual clapi_ key

When you exceed a limit you get a 429 with a Retry-After header and a rate_limited error body. See Errors & Rate Limits.

Credits & the quote model

Reads (search filters, list reads, status polls, exports, whoami, balance) are free. Search defers a small per-lead charge to enrichment/save time. Paid bulk operations — bulk enrichment, smart agents, CRM/sequencer sync, CSV import — require a signed quote:

  1. Call POST /credits/estimate with the operation shape. You get back a quote_id (HMAC-signed, 5-minute TTL) and the estimated_cost.
  2. Pass that quote_id to the paid endpoint. The server recomputes the cost and rejects with spend_cap_exceeded if it would exceed the quote.

See Credits for balances, estimates, usage reporting, and the full cost table.

Quick start

A complete flow: generate a key, estimate a bulk enrichment, run it, then poll for completion.

# 1. Generate a key (Clerk JWT auth — usually done once in the portal)
curl -X POST https://api.cleanlist.ai/api/v1/api-keys \
  -H "Authorization: Bearer <clerk_session_jwt>" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production server"}'
 
# 2. Confirm identity, scopes, and tier
curl https://api.cleanlist.ai/api/v1/public/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/v1/public/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/v1/public/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/v1/public/enrichment/status/WORKFLOW_ID \
  -H "Authorization: Bearer clapi_your_api_key"

Endpoint index

All paths below are relative to https://api.cleanlist.ai/api/v1/public unless noted. The Scope column lists the OAuth scope each endpoint requires.

Workspace & identity

MethodPathScope
GET/whoaminone (any valid credential)
GET/credits/balancecredits:read
POST/credits/estimatecredits:read
GET/api-keysadmin:api_keys
GET/usageadmin:api_keys

Search

MethodPathScope
GET/search/people/filterspeople:read
POST/search/peoplepeople:read
GET/search/companies/filterscompanies:read
POST/search/companiescompanies:read
POST/search/companies/similarcompanies:read

Lead lists

MethodPathScope
POST/lead-listslists:write
GET/lead-listslists:read
GET/lead-lists/{list_id}lists:read
GET/lead-lists/{list_id}/leadslists:read
POST/lead-lists/{list_id}/leadslists:write
DELETE/lead-lists/{list_id}/leadslists:write
POST/lead-lists/{list_id}/csv-importlists:write (+ enrich:write if dispatching)

Enrichment

MethodPathScope
POST/enrichment/personenrich:write
POST/enrichment/companyenrich:write
POST/enrichment/by-taskenrich:write
POST/enrichment/bulkenrich:write
GET/enrichment/status/{workflow_id}enrich:read

Smart agents

MethodPathScope
POST/smart-agents/runsmart_agents:write
GET/smart-agentssmart_agents:read
GET/smart-agents/{smart_agent_task_id}smart_agents:read

Sync & export

MethodPathScope
POST/sync/crmsync:write
POST/sync/sequencersync:write
POST/export/csv/signed-urlexport:read
GET/export/jsonexport:read

API key management (Clerk JWT)

MethodPath
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

whoami

The fastest way to confirm a credential works and see what it can do:

curl https://api.cleanlist.ai/api/v1/public/whoami \
  -H "Authorization: Bearer clapi_your_api_key"
{
  "user_email": "v***@cleanlist.ai",
  "user_id": "user_2abc...",
  "user_name": "Victor Paraschiv",
  "organization_id": "org_2xyz...",
  "organization_name": "Cleanlist",
  "auth_type": "api_key",
  "scopes": ["people:read", "lists:read", "lists:write", "enrich:read", "enrich:write", "credits:read"],
  "tier": "pro",
  "features": ["api_access", "data_source_csv_upload"],
  "timestamp_ms": 1717430400000
}

For api_key auth, user_email is masked so a leaked key can't reveal the creator's full address.

Learn more