> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zixflow.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CSV Import Introduction

> Import people, events, and devices from a publicly reachable HTTPS CSV URL

Import people, events, and devices from a **publicly reachable HTTPS CSV URL**. The API queues the job and returns immediately. Poll status until the job finishes.

## Base path

All import endpoints are under the Data API:

```
https://api-ai.zixflow.com/api/data
```

## Authentication

Import requests use the same header-based auth as other Zixflow AI Data APIs. The API key must have the **Dashboard** permission. See [Authentication](/api-reference/zixflow-ai/authentication).

```
x-api-key: <your-api-key>
x-workspace-id: <your-workspace-id>
Content-Type: application/json
```

`x-workspace-id` must be the workspace that owns the API key.

| Status | When |
| - | - |
| `401` | Missing/invalid key, missing workspace header, or workspace mismatch |
| `403` | Key is valid but does not have **Dashboard** permission |

Auth failures look like:

```json theme={null}
{ "error": true, "message": "Unauthorized" }
```

Handler errors (validation, not found, rate limit, etc.) look like:

```json theme={null}
{ "success": false, "message": "file_url must be a valid https url" }
```

## Daily limit

Shared daily limit across **people + events + devices**: plan default is **10 imports per UTC day** (`max_import_requests_per_day`). Cancelling a job that is still `in-queue` refunds one slot.

## How import works

1. Host a CSV that returns **raw CSV bytes** over HTTPS (not an HTML share/preview page).
2. `POST` the file URL and column mapping.
3. The API creates a job with status `in-queue` and returns `import_id`.
4. `GET` status until `completed`, `failed`, or `cancelled`.
5. If rows failed, `error_file_url` is a signed CSV of error rows (refreshed on poll; \~7 day expiry).

You can cancel only while status is `in-queue`. Once processing has started, cancel returns `409`.

### Job statuses

| Status | Meaning |
| - | - |
| `in-queue` | Queued; cancel is allowed |
| `in-progress` | Worker is processing |
| `completed` | Finished |
| `failed` | Job failed |
| `cancelled` | Cancelled from `in-queue` |

### Get mapping from the dashboard (recommended)

Hand-writing `mapping` is error-prone — system and custom attribute keys must match exactly. The simplest approach is to build the mapping once in the web app, then paste that JSON into your API request.

1. Open [ai.zixflow.com](https://ai.zixflow.com) and start a manual import for **Users**, **Events**, or **Devices**.
2. Complete the three steps below until Review shows the mapping JSON.
3. Copy (or export) that JSON and send it as the `mapping` field of your import API request.
4. You can cancel the dashboard import after copying — you only need the mapping for the API.

#### Stage 1 — Upload file

Choose what to import (Users / Events / Devices), then upload or drop your CSV.

![Import data stage 1 — upload CSV and choose Users, Events, or Devices](https://res.cloudinary.com/salessimplifyimg/image/upload/v1791544063/Zixflow%20API%20Doc/Screenshot_2026-10-09_at_4.36.58_PM_kqilvh.png)

#### Stage 2 — Map columns

Map each CSV column to a system or custom attribute. Auto-match helps, and you can import a saved mapping JSON if you already have one.

![Import data stage 2 — map CSV columns to attributes](https://res.cloudinary.com/salessimplifyimg/image/upload/v1791544063/Zixflow%20API%20Doc/Screenshot_2026-10-09_at_4.37.20_PM_oxsbve.png)

#### Stage 3 — Review and copy mapping

On **Review & import**, use the **mapping JSON** block labeled for API use. Copy it or click **Export mapping JSON**, then send that array as `mapping` in your API body.

![Import data stage 3 — copy mapping JSON for the API](https://res.cloudinary.com/salessimplifyimg/image/upload/v1791544064/Zixflow%20API%20Doc/Screenshot_2026-10-09_at_4.37.29_PM_dazwr1.png)

Example of a mapping copied from the dashboard:

```json theme={null}
[
  { "csv_column": "user_id", "attribute": "user_id" },
  { "csv_column": "email", "attribute": "email" },
  { "csv_column": "phone", "attribute": "phone" }
]
```

### Mapping rules (all modules)

* Always generate `mapping` from the dashboard steps above. Attribute keys include system and custom fields for your workspace and are not listed here.
* `mapping` is required and must not be empty.
* Each item needs `csv_column` and `attribute` (required attribute key).
* CSV column names and attribute keys must be unique (case-insensitive).
* `csv_column` must match the CSV header exactly.

### `file_url` rules

* Required
* Must be a valid `https://` URL with a host
* Must return raw CSV bytes when fetched

## Endpoints

| Method | Path | Description |
| - | - | - |
| `POST` | `/people/v1/import` | [Queue people CSV import](/api-reference/zixflow-ai/import/people/create) |
| `GET` | `/people/v1/import/{import_id}` | [People import status](/api-reference/zixflow-ai/import/people/get-status) |
| `POST` | `/people/v1/import/{import_id}/cancel` | [Cancel queued people import](/api-reference/zixflow-ai/import/people/cancel) |
| `POST` | `/events/v1/import` | [Queue events CSV import](/api-reference/zixflow-ai/import/events/create) |
| `GET` | `/events/v1/import/{import_id}` | [Events import status](/api-reference/zixflow-ai/import/events/get-status) |
| `POST` | `/events/v1/import/{import_id}/cancel` | [Cancel queued events import](/api-reference/zixflow-ai/import/events/cancel) |
| `POST` | `/devices/v1/import` | [Queue devices CSV import](/api-reference/zixflow-ai/import/devices/create) |
| `GET` | `/devices/v1/import/{import_id}` | [Devices import status](/api-reference/zixflow-ai/import/devices/get-status) |
| `POST` | `/devices/v1/import/{import_id}/cancel` | [Cancel queued devices import](/api-reference/zixflow-ai/import/devices/cancel) |

## Suggested poll loop

1. Create import → store `data.import_id`.
2. Poll `GET …/import/{import_id}` every few seconds.
3. Stop on `completed`, `failed`, or `cancelled`.
4. If `failed` > 0 or you need row-level errors, download `error_file_url`.

Do not cancel after `in-progress`. That request will fail with `409` and will not refund a daily slot.

## Shared error table

| Status | Meaning |
| - | - |
| `400` | Invalid body, URL, mapping, ids, or segment type |
| `401` | Auth failed |
| `403` | API key missing dashboard permission |
| `404` | Import or segment not found |
| `409` | Cancel requested after the job left `in-queue` |
| `429` | Daily public API import limit reached |
| `500` | Failed to create/queue/load the job |
| `503` | Message broker unavailable |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.