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

# Data Ingestion

> Endpoints for uploading and updating data in Cognee Cloud

These endpoints add data to your Cognee Cloud tenant. All require authentication via API key.

For the underlying concepts, see [Remember](/core-concepts/main-operations/remember) and [Add](/core-concepts/main-operations/legacy-operations/add).

## Remember

**`POST /api/v1/remember`** — Ingest data and build the knowledge graph in a single call.

Combines the add and cognify steps. Equivalent to calling `cognee.remember()` in the Python SDK. Accepts multipart form data. For most workflows, `remember` is the simplest entry point; use the lower-level `add` + `cognify` operations separately when you need to upload multiple files before triggering processing.

```bash theme={null}
curl -X POST https://your-tenant.aws.cognee.ai/api/v1/remember \
  -H "X-Api-Key: your-key" \
  -F "data=@document.pdf" \
  -F "datasetName=my_dataset"
```

| Parameter           | Type          | Required | Description                                                                                                                                                                                                                            |
| ------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`              | file(s)       | yes      | One or more files to upload                                                                                                                                                                                                            |
| `labels`            | string (JSON) | no       | JSON array of per-file labels, paired positionally with `data` — see [how per-file labels and metadata work](#how-per-file-labels-and-metadata-work). Rejected with `400` when combined with `session_id` or `content_type`.           |
| `external_metadata` | string (JSON) | no       | JSON array of per-file metadata objects, paired positionally with `data` — see [how per-file labels and metadata work](#how-per-file-labels-and-metadata-work). Rejected with `400` when combined with `session_id` or `content_type`. |
| `datasetName`       | string        | no       | Target dataset name                                                                                                                                                                                                                    |
| `datasetId`         | UUID          | no       | Existing dataset UUID                                                                                                                                                                                                                  |
| `session_id`        | string        | no       | Session identifier for grouping operations                                                                                                                                                                                             |
| `node_set`          | string\[]     | no       | Node identifiers                                                                                                                                                                                                                       |
| `run_in_background` | boolean       | no       | Run asynchronously (default: `false`)                                                                                                                                                                                                  |
| `custom_prompt`     | string        | no       | Custom extraction prompt                                                                                                                                                                                                               |
| `chunks_per_batch`  | integer       | no       | Chunks per batch (default: `10`)                                                                                                                                                                                                       |
| `graph_model`       | string        | no       | JSON-serialised graph model schema (same format as cognify), including a top-level `title` key. Leave empty to use the default `KnowledgeGraph` model.                                                                                 |
| `content_type`      | string        | no       | Set to `skills` to ingest SKILL.md files as Skill nodes. Only `skills` is supported; leave empty for normal ingestion.                                                                                                                 |

On a completed run, the response includes `items_processed` — the count of successfully ingested items (entries whose pipeline run did not error).

### Error responses

| Status | When                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Neither `datasetName` nor `datasetId` was provided, an unsupported `content_type` was sent (anything other than empty or `skills`), or `graph_model` was not valid JSON or could not be converted to a graph model schema. Also returned when `labels` is a JSON array containing non-string entries (a value that does not parse as a JSON array is read as comma-separated labels rather than rejected), when `external_metadata` is not a JSON array of objects or contains the reserved key `node_set`, when the number of `labels` or `external_metadata` entries does not match the number of uploaded files, or when either field is combined with `session_id` or `content_type`. |
| `402`  | The configured LLM provider (or LiteLLM proxy) reported that its token budget is exhausted. The response body is `{"detail": "LLM provider requires payment or token budget is exhausted. [LLMPaymentRequiredError]"}`. Handle 402 by surfacing a top-up / billing flow rather than retrying.                                                                                                                                                                                                                                                                                                                                                                                             |
| `403`  | You lack write access to the target dataset. The response body is `{"detail": "<message> [PermissionDeniedError]"}`. This also applies to COGX archive imports, where a permission denial previously collapsed into a generic `409`.                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `409`  | The remember run failed during processing, or a blocking (non-background) run finished in an `errored` state. The response body carries the underlying pipeline or validation error message. Cognee's own errors no longer land here — they keep their own status code.                                                                                                                                                                                                                                                                                                                                                                                                                   |

<Note>
  A `graph_model` that is invalid JSON or cannot be converted to a schema is now rejected with `400` rather than being silently ignored. Empty optional fields (`content_type`, `graph_model`, `session_id`, `node_set` entries) are treated as omitted.
</Note>

### How per-file labels and metadata work

`POST /api/v1/remember` and [`POST /api/v1/add`](#add) both accept two optional form fields that attach a label and arbitrary metadata to each uploaded file. They are the HTTP equivalent of the Python SDK's [`DataItem(label=..., external_metadata=...)`](/core-concepts/main-operations/legacy-operations/add).

Each field is sent as a **single JSON part**, not one part per file, because multipart clients cannot reliably repeat an array form field. Entries pair **positionally** with the uploaded files: the Nth entry applies to the Nth file.

| Field               | Format                                                            | Skipping a file |
| ------------------- | ----------------------------------------------------------------- | --------------- |
| `labels`            | JSON array of strings — `["finance", "people", ""]`               | Empty string    |
| `external_metadata` | JSON array of objects — `[{"source": "crm", "ticket": 42}, null]` | `null` or `{}`  |

```bash theme={null}
curl -X POST https://your-tenant.aws.cognee.ai/api/v1/remember \
  -H "X-Api-Key: your-key" \
  -F "data=@q4-earnings.pdf" \
  -F "data=@team-roster.csv" \
  -F 'labels=["q4-earnings", "people"]' \
  -F 'external_metadata=[{"source": "crm", "ticket": 42}, null]' \
  -F "datasetName=my_dataset"
```

When either field carries at least one non-empty entry, it must have exactly one entry per uploaded file — a partial list is ambiguous and returns `400`. `external_metadata` is merged into the file's stored metadata, with your keys taking precedence over loader-derived ones; `node_set` is reserved and rejected, so use the `node_set` form field instead.

Saved values are returned by [`GET /api/v1/datasets/{dataset_id}/data`](/cognee-cloud/functionality/dataset-management#dataset-data) as `label` and `externalMetadata`.

<Note>
  **Swagger UI caveat.** Typing a JSON array of strings into the `labels` field in Swagger UI sends it as a comma-joined string (`finance,people,`). The endpoint accepts that form equivalently, so try-it-out works — but it means a label cannot contain a comma unless your client sends real JSON. `external_metadata` has no comma-separated fallback: it must always be valid JSON.
</Note>

## Lower-level operations

The following endpoints provide more granular control over data ingestion. Most users should prefer `remember` above.

### Add

**`POST /api/v1/add`** — Upload files to a dataset without processing.

Accepts multipart form data. Files are stored in the dataset but not yet processed into the knowledge graph — call [cognify](/cognee-cloud/functionality/knowledge-processing#cognify) separately.

```bash theme={null}
curl -X POST https://your-tenant.aws.cognee.ai/api/v1/add \
  -H "X-Api-Key: your-key" \
  -F "data=@document.pdf" \
  -F "datasetName=my_dataset"
```

| Parameter           | Type          | Required | Description                                                                                                                                                    |
| ------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`              | file(s)       | yes      | One or more files to upload                                                                                                                                    |
| `labels`            | string (JSON) | no       | JSON array of per-file labels, paired positionally with `data` — see [how per-file labels and metadata work](#how-per-file-labels-and-metadata-work)           |
| `external_metadata` | string (JSON) | no       | JSON array of per-file metadata objects, paired positionally with `data` — see [how per-file labels and metadata work](#how-per-file-labels-and-metadata-work) |
| `datasetName`       | string        | no       | Target dataset name (created if it does not exist). Required unless `datasetId` is given.                                                                      |
| `datasetId`         | UUID          | no       | Existing dataset UUID                                                                                                                                          |
| `node_set`          | string\[]     | no       | Node identifiers                                                                                                                                               |
| `run_in_background` | boolean       | no       | Run asynchronously (default: `false`)                                                                                                                          |

Unlike `remember`, `add` has no `session_id` or `content_type`, so `labels` and `external_metadata` are always available here.

Supported file types:

* **Documents** — PDF, TXT, Markdown, CSV, JSON, DOCX, PPTX
* **Images** — PNG, JPG, JPEG, GIF, WEBP, TIFF, BMP, and more, extracted via the tenant's configured vision model
* **Audio** — MP3, WAV, M4A, OGG, FLAC, and more, transcribed to text

Images and audio are converted to text using the tenant's configured LLM before the knowledge graph is built, so they are ingested the same way as text documents. The same file types apply to `POST /api/v1/remember`.

### Update

**`PATCH /api/v1/update`** — Replace an existing document in a dataset.

Accepts multipart form data. Requires both the data item ID and dataset ID as query parameters.

```bash theme={null}
curl -X PATCH "https://your-tenant.aws.cognee.ai/api/v1/update?data_id=<uuid>&dataset_id=<uuid>" \
  -H "X-Api-Key: your-key" \
  -F "data=@updated_document.pdf"
```

| Parameter    | Location | Type      | Required | Description                               |
| ------------ | -------- | --------- | -------- | ----------------------------------------- |
| `data_id`    | query    | UUID      | yes      | ID of the document to replace             |
| `dataset_id` | query    | UUID      | yes      | ID of the dataset containing the document |
| `data`       | form     | file(s)   | yes      | Replacement file(s)                       |
| `node_set`   | form     | string\[] | no       | Node identifiers                          |
