Documentation
Any people search filter set, up to 50,000 rows per export, delivered as a plain .csv — never zipped, never compressed — with an email when it is ready. Always asynchronous: a request is admitted or refused on the spot, and a worker does the walk.
POST /v1/exports · needs the search scope, plus enrich when the columns reveal contact points
The body is { filters, limit, preset | columns, caps?, reveal?, name? }. filters is any people-search filter set without the paging fields (cursor, limit, count, facets). limit is how many rows you want; the export stops there or at the end of the result, whichever comes first.
curl -X POST https://api.leadocean.io/v1/exports \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"name": "CTOs in Germany",
"filters": { "title": ["CTO"], "country": ["DE"], "emailStatus": ["verified"] },
"limit": 5000,
"preset": "full"
}'HTTP 202
{
"success": true,
"data": {
"id": "68d5f1c2a9b3e40012ab34cd",
"name": "CTOs in Germany",
"status": "queued",
"requested": 5000,
"estimatedTotal": 18342,
"reveal": "email_phone",
"columns": ["person_id", "person_group_id", "…61 ids…"],
"perRow": 1,
"remaining": 89990,
"pollAfter": 10,
"file": null
}
}The answer is 202 with the job. perRow is what each row costs in records — always 1 — remaining is what the account has left after this reservation, estimatedTotal is how many people matched when the job was admitted.
GET /v1/exports/columns (free, public) lists every column id, its group, and whether it is on the search row. Two presets name a set for you:
full — the default. 45 columns: identity, profile, address, contact flags, up to three emails and two phones, the current role, education and skills. Reveals emails and phones, so it needs the enrich scope.search — the 27 columns a search result already carries: identity, headline, location, current employer and title, and the contact flags (has an email, email status) but never an address. No enrich scope needed.Or send columns, an ordered list of ids, for exactly the set you want. Repeated blocks — emails, phones, past roles, schools, certifications, awards — become numbered columns (email_1_address, email_2_address, …); caps sets how many of each (defaults: emails 3, phones 2, past 3, educations 2, certifications 2, awards 1).
Two honesties about the profile text: about half of the summaries were stored by the crawl as a preview and end in an ellipsis, and an education entry is the institution and degree as one line of text, not separate fields. Certifications are not in the default: the index holds them as one unsplittable string, so the columns exist in the catalogue but stay empty.
GET /v1/exports/{id} · free
GET /v1/exports/{id}/download · free · text/csv
DELETE /v1/exports/{id} · cancel
GET /v1/exports?status=&limit=&cursor= · list, newest first
| status | Meaning |
|---|---|
queued | Admitted. The rows are reserved against your ceilings and your records from this moment. |
running | The worker is walking the search and writing the file. rows counts up; a cancel stops it at the next checkpoint and keeps what is written. |
done | The file is on storage. file.bytes, file.sha256 and file.expiresAt are set; download it with your key or the emailed link. |
failed | Something broke mid-way. error.code says what; the rows that were written are still downloadable and are the only ones billed. |
cancelled | You stopped it. Rows written stay billed and downloadable; rows never written are released. |
Poll every pollAfter seconds (10). When status is done, GET …/download streams the file with your key. The ready email carries a link that works without a key for 24 hours; the file itself is kept for 7 days, then deleted — file.expiresAt says when.
Rows are billed as they are written, at checkpoints: a job that fails or is cancelled after 12,000 rows bills 12,000, and the rest of the reservation is released (released on the job).
Three ceilings sit on top of your records: 50,000 rows per export, 500,000 rows a day and 10,000,000 rows a billing period, per account. They count rows already reserved by exports still going plus rows written by finished ones, so twenty parallel starts cannot overshoot. They can be raised for an account — write to support@leadocean.io. GET /v1/usage reports where you stand under exports.
| Status | code | Why |
|---|---|---|
| 400 | export_limit_rows | limit is above the per-export ceiling (50,000 by default). |
| 400 | export_filter_unsupported | A filter in the set cannot be applied by the index. details.filters names it. An export is never run half-filtered. |
| 429 | export_limit_daily / export_limit_monthly | The account has reached its rows for the day (500,000) or the period (10,000,000). details.remaining and details.resetsAt say how much and when. |
| 402 | quota | limit is more than the records you have left this period. The message quotes both figures. |
| 403 | scope | The column set reveals emails or phones and the key does not hold the enrich scope. |
| 503 | export_storage_unavailable | Object storage is unreachable. Transient; nothing is reserved. |
One export runs per account at a time; the rest queue in order, already reserved and already counted.
The same jobs are on the Exports page — the filter builder, a column picker with the presets, the price before you start, and a Download button — and on MCP as leadocean_export_leads, leadocean_get_export and leadocean_list_exports. An agent can start an export from a conversation and hand back the download link when it is ready.