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

# Ingest Export

> Upload and process an LLM conversation data export.

## `POST /api/ingest-export`

Ingests a conversation data export (JSON) for a given connection. The export file is normalized into individual conversations with a consistent `{ role, content, timestamp }` message format and stored in the Verso database.

Currently supports ChatGPT export format (DAG → linear message list normalization).

## Request

**Headers**

| Header          | Value                    |
| --------------- | ------------------------ |
| `Authorization` | `Bearer YOUR_APP_SECRET` |
| `Content-Type`  | `application/json`       |

**Body**

```json theme={null}
{
  "appId": "app_yourapp",
  "connectionId": "uuid",
  "conversations": [
    {
      "title": "Conversation title",
      "create_time": 1700000000,
      "update_time": 1700001000,
      "mapping": { "..." : "..." },
      "conversation_id": "chatgpt-uuid"
    }
  ]
}
```

| Field           | Type     | Required | Description                                       |
| --------------- | -------- | -------- | ------------------------------------------------- |
| `appId`         | `string` | Yes      | Your app identifier                               |
| `connectionId`  | `string` | Yes      | The connection to associate data with             |
| `conversations` | `array`  | Yes      | Array of raw conversation objects from the export |

## Processing

The endpoint performs a **diff/upsert** for each conversation:

1. **Normalize** — raw export data is converted to `NormalizedConversation` (linear message list)
2. **Check existing** — looks up by `(connection_id, external_id)`
3. **Insert** — if no existing record
4. **Update** — if existing record has an older `update_time`
5. **Skip** — if existing record is the same or newer

After processing, the connection's `last_ok_at` is updated. If any conversations were inserted or updated, a `data.imported` webhook is enqueued.

## Response

```json theme={null}
{
  "ok": true,
  "inserted": 42,
  "updated": 3,
  "unchanged": 0,
  "total": 45
}
```

| Field       | Type      | Description                                    |
| ----------- | --------- | ---------------------------------------------- |
| `ok`        | `boolean` | Always `true` on success                       |
| `inserted`  | `number`  | New conversations inserted                     |
| `updated`   | `number`  | Existing conversations updated (newer version) |
| `unchanged` | `number`  | Conversations skipped (same or older version)  |
| `total`     | `number`  | Total conversations in the export              |

## Errors

| Status | Error                                     | Cause                                            |
| ------ | ----------------------------------------- | ------------------------------------------------ |
| 400    | `Missing appId`                           | `appId` field not provided                       |
| 400    | `Missing connectionId`                    | `connectionId` field not provided                |
| 400    | `Invalid JSON body`                       | Request body is not valid JSON                   |
| 400    | `[normalization error]`                   | Export data could not be normalized              |
| 401    | `Missing or invalid Authorization header` | Missing `Bearer` prefix                          |
| 401    | `Invalid API key`                         | Wrong or missing app secret                      |
| 403    | `Connection does not belong to this app`  | Connection exists but belongs to a different app |
| 404    | `App not found`                           | App ID doesn't exist                             |
| 404    | `Connection not found`                    | Connection ID doesn't exist                      |
| 405    | `Method not allowed`                      | Must use `POST`                                  |
| 409    | `Connection is revoked`                   | Connection was deleted                           |
