# Export lists as CSV

Source: https://docs.emelia.io/docs/lists/export-lists-as-csv

Guide: [Lists & contacts](https://docs.emelia.io/docs/lists.md)

`POST https://api.emelia.io/lists/list/export`

Exports one list as a CSV file, or several lists as a ZIP archive with one CSV per list.

CSV format: UTF-8 with BOM, comma separator, CRLF line endings. Columns: `First Name`, `Last Name`, `Full Name`, `Email`, `Phone`, `Mobile Phone`, `Job Title`, `LinkedIn URL`, `Bio`, `Company`, `Website`, `LinkedIn Page`, `Company Size`, `Industry`, `Country`, `Region`, `City`, `Status`, `Handle`, then one column per custom variable of the account (display name), then `Lists` and `Campaigns` (one `Campaign name - STATUS` line per campaign). Company-only lists use a shorter header (`Company`, `Website`, `LinkedIn Page`, `Company Size`, `Industry`, custom variables, `Lists`).

`leadIds`, `search`, `statuses` and `filters` only apply when exactly one list is exported; they are ignored for a multi-list ZIP. List ids that are not yours are silently skipped.

**Large exports**: send `async: true`. If the export covers more than 5,000 contacts, the response is `202` with a `jobId`: poll `GET /lists/list/export/jobs/{jobId}` until `status` is `done`, then download the file. At or under 5,000 contacts the file is returned directly (200) even with `async: true`, so handle both responses. With `async: true`, an export above 100,000 contacts is refused (422). Only one asynchronous export runs per account: while one is queued or running, a new request returns that existing job (it may concern other lists). Without `async`, the file is always streamed synchronously, whatever its size, and the connection may be cut after 120 seconds of silence.

## Authentication

Send your API key in the `Authorization` header: `Authorization: <your API key>`.

## Request body

Content type: `application/json`, required.

| Field | Type | Required | Description |
|---|---|---|---|
| `listIds` | array of string | yes | Lists to export, in the order of the ZIP. Invalid ids and lists that are not yours are skipped. |
| `leadIds` | array of string | no | Export only these contacts (single-list export only). |
| `search` | string | no | Same as `search` of the rows route (single-list export only). |
| `statuses` | array of string | no | Engagement statuses, `NO_ACTIVITY` included (single-list export only). |
| `filters` | array of object | no | Column filters (single-list export only). Max 10 items. |
| `filters[].column` | string | yes | Contact columns: `firstName`, `lastName`, `fullName`, `jobTitle`, `email`, `secondaryEmail`, `phone`, `mobilePhone`, `linkedinUrlProfile`, `twitterUrl`, `country`, `city`, `seniority`, `department`, `bio`, `gender`, `emailVerified`. Company columns: `companyName`, `companyDomain`, `websiteUrl`, `industry`, `linkedinCompanyUrl`, `companyCountry`, `companyCity`. Custom variables: `custom<TechnicalName>`. |
| `filters[].operator` | enum: `equals`, `not_equals`, `contains`, `not_contains`, `empty`, `not_empty` | yes |  |
| `filters[].value` | string | no | Required except for `empty` and `not_empty`. |
| `async` | boolean | no | Allow an asynchronous job (202) when the export covers more than 5,000 contacts. Default: `false`. |

```json
{
  "listIds": [
    "string"
  ],
  "leadIds": [
    "string"
  ],
  "search": "string",
  "statuses": [
    "string"
  ],
  "filters": [
    {
      "column": "string",
      "operator": "equals",
      "value": "string"
    }
  ],
  "async": false
}
```

## Example request

**cURL**

```bash
curl -X POST "https://api.emelia.io/lists/list/export" \
  -H "Authorization: $EMELIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "listIds": [
    "string"
  ],
  "leadIds": [
    "string"
  ],
  "search": "string",
  "statuses": [
    "string"
  ],
  "filters": [
    {
      "column": "string",
      "operator": "equals",
      "value": "string"
    }
  ],
  "async": false
}'
```

**JavaScript**

```js
const response = await fetch('https://api.emelia.io/lists/list/export', {
  method: 'POST',
  headers: { Authorization: process.env.EMELIA_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "listIds": [
      "string"
    ],
    "leadIds": [
      "string"
    ],
    "search": "string",
    "statuses": [
      "string"
    ],
    "filters": [
      {
        "column": "string",
        "operator": "equals",
        "value": "string"
      }
    ],
    "async": false
  }),
});
console.log(await response.json());
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://api.emelia.io/lists/list/export",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
    json={
        "listIds": [
            "string"
        ],
        "leadIds": [
            "string"
        ],
        "search": "string",
        "statuses": [
            "string"
        ],
        "filters": [
            {
                "column": "string",
                "operator": "equals",
                "value": "string"
            }
        ],
        "async": False
    },
)
print(response.json())
```

## Responses

### 200: The file: `text/csv; charset=utf-8` named after the list for one list, `application/zip` named `emelia-lists-export.zip` for several lists. Sent as an attachment (`Content-Disposition`).

Content type: `text/csv`.

### 202: Asynchronous export accepted (only with `async: true` and more than 5,000 contacts). `total` is the number of contacts of this request; if an export was already running, `jobId` and `status` are those of that running export.

| Field | Type | Required | Description |
|---|---|---|---|
| `jobId` | string (uuid) | yes |  |
| `status` | enum: `queued`, `running`, `done`, `failed` | yes |  |
| `total` | integer | yes | Contacts covered by this request (estimate based on the list counters). |

```json
{
  "jobId": "0b6f3c1e-8a2d-4c5b-9e7f-1a2b3c4d5e6f",
  "status": "queued",
  "total": 18250
}
```

### 400: No valid list id.

| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | yes | English, human-readable message. |
| `code` | string | no | Stable error code, when available (for example `PAYLOAD_TOO_LARGE`, `INVALID_JSON`, `export_too_large`, `companies_only`, `enrichment_running`). |
| `params` | object | no |  |
| `error` | string | no | Raw internal message (unexpected errors only). |

```json
{
  "message": "listIds is required"
}
```

### 401: Missing, unknown or disabled API key, or the account of the key no longer exists. Note the body shape: `error` and `code`, not `message`.

| Field | Type | Required | Description |
|---|---|---|---|
| `error` | string | yes |  |
| `code` | enum: `AUTH_REQUIRED`, `ACCOUNT_NOT_FOUND` | yes |  |

```json
{
  "error": "string",
  "code": "AUTH_REQUIRED"
}
```

### 404: None of the requested lists is yours.

| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | yes | English, human-readable message. |
| `code` | string | no | Stable error code, when available (for example `PAYLOAD_TOO_LARGE`, `INVALID_JSON`, `export_too_large`, `companies_only`, `enrichment_running`). |
| `params` | object | no |  |
| `error` | string | no | Raw internal message (unexpected errors only). |

```json
{
  "message": "No matching list found"
}
```

### 422: Invalid `filters`, or export too large (with `async: true`).

| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | yes | English, human-readable message. |
| `code` | string | no | Stable error code, when available (for example `PAYLOAD_TOO_LARGE`, `INVALID_JSON`, `export_too_large`, `companies_only`, `enrichment_running`). |
| `params` | object | no |  |
| `error` | string | no | Raw internal message (unexpected errors only). |

```json
{
  "message": "string",
  "code": "string",
  "params": {},
  "error": "string"
}
```

### 500: Export failed before the file started.

| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | yes | English, human-readable message. |
| `code` | string | no | Stable error code, when available (for example `PAYLOAD_TOO_LARGE`, `INVALID_JSON`, `export_too_large`, `companies_only`, `enrichment_running`). |
| `params` | object | no |  |
| `error` | string | no | Raw internal message (unexpected errors only). |

```json
{
  "message": "Export failed",
  "error": "List not found"
}
```

### 503: Asynchronous export temporarily unavailable (job storage down). Retry later.

| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | yes | English, human-readable message. |
| `code` | string | no | Stable error code, when available (for example `PAYLOAD_TOO_LARGE`, `INVALID_JSON`, `export_too_large`, `companies_only`, `enrichment_running`). |
| `params` | object | no |  |
| `error` | string | no | Raw internal message (unexpected errors only). |

```json
{
  "message": "Async export unavailable"
}
```
