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: POST /export/csv/signed-url builds a CSV of a list and returns a download link valid for 24 hours. GET /export/json returns leads inline, up to 500 per call, with cursor paging. Both need export:read and are free.
Export
Two ways to get a lead list out of Cleanlist through API v2. To export from the app instead, see Exporting data.
| Endpoint | Method | Scope | Cost |
|---|---|---|---|
| CSV (signed URL) | POST /export/csv/signed-url | export:read | Free |
| JSON | GET /export/json | export:read | Free |
Columns
Both endpoints use the same columns. Without columns, you get the default set, in this order:
| Column | Contents |
|---|---|
lead_id | Lead id |
first_name, last_name | Name |
email | Primary email (empty until enriched) |
title | Job title |
company | Company name |
domain | Company domain |
linkedin_url | LinkedIn profile URL |
phone | First phone number (empty until phone-enriched) |
location | City and country |
Pass columns to pick a subset and set the order. Stick to these names; other names may come back empty.
CSV export
POST /export/csv/signed-url
Scope: export:read · Cost: free
Builds a CSV of the whole list, uploads it, and returns a signed link.
Request body
| Field | Type | Notes |
|---|---|---|
list_id | string | Required. A list you can read |
columns | string[] | Optional ordered subset of the columns above |
include_smart_agents | boolean | Default true: adds one column per skill or smart-agent result saved on the list (headed by its display name) after your columns. false exports only the base columns |
curl -X POST https://api.cleanlist.ai/api/v2/export/csv/signed-url \
-H "Authorization: Bearer clapi_your_api_key" \
-H "Content-Type: application/json" \
-d '{"list_id": "LIST_ID", "columns": ["first_name", "last_name", "email", "company"]}'Response
{
"list_id": "LIST_ID",
"download_url": "https://...",
"expires_at": "2026-10-08T21:20:00+00:00",
"row_count": 1284,
"file_size_bytes": 402118
}| Field | Meaning |
|---|---|
download_url | Signed link to the CSV file. Anyone with the link can download it until it expires, so treat it like a secret |
expires_at | When the link stops working, 24 hours after it was made |
row_count | Data rows in the file (not counting the header) |
file_size_bytes | File size |
To stop spreadsheet apps from running formulas, any cell that starts with =, +, - or @ is written with a leading apostrophe (').
With an SDK: export.export_csv(...) and export.export_json(...) (exportCsv and exportJson in TS and Java). See the SDKs.
JSON export
GET /export/json
Scope: export:read · Cost: free
Returns a page of the list's leads inline, using the same columns.
| Query param | Default | Notes |
|---|---|---|
list_id | none | Required |
limit | 100 | 1 to 500 rows per call |
cursor | none | The cursor from the previous response |
columns | default set | Repeat the parameter for each column, for example columns=email&columns=company |
curl "https://api.cleanlist.ai/api/v2/export/json?list_id=LIST_ID&limit=500" \
-H "Authorization: Bearer clapi_your_api_key"{
"list_id": "LIST_ID",
"leads": [
{ "lead_id": "lead_5f9d2b", "first_name": "Ada", "last_name": "Lovelace", "email": "ada@analytical.io", "company": "Analytical", "domain": "analytical.io" }
],
"total": 1284,
"cursor": "500",
"timestamp_ms": 1751404800000
}Pass cursor back to get the next page; it's null on the last page. total is the number of leads in the whole list. A malformed cursor returns 400 invalid_cursor instead of starting over.
Errors
| Code | HTTP | Cause |
|---|---|---|
insufficient_scope | 403 | The credential lacks export:read |
list_not_found | 404 | Unknown list, or a private list you can't access |
invalid_cursor | 400 | The JSON cursor isn't one the API returned |
internal_error | 502 | The export couldn't be built or uploaded; retry |