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

# Update & Delete Data

> Update document metadata and delete documents, collections, and objects — including what cascades

How to change and remove data after ingestion, and exactly what each delete cascades to.

## Update document metadata

`PATCH` a document to change its fields. The body is a partial update — send **only the fields you want to change**; you never resend vectors. Any fields you pass are merged into the document.

```bash theme={null}
curl -sS -X PATCH \
  "$MP_API_URL/v1/collections/$COLLECTION_ID/documents/$DOCUMENT_ID" \
  -H "Authorization: Bearer $MP_API_KEY" \
  -H "X-Namespace: $MP_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{ "status": "reviewed", "priority": 3 }'
```

### Set and remove metadata keys

`PUT` and `PATCH` treat `metadata` the same way. Each key you send is set on the stored
metadata. Keys you omit stay as they are. A key set to `null` is removed.

```bash theme={null}
curl -sS -X PATCH \
  "$MP_API_URL/v1/collections/$COLLECTION_ID/documents/$DOCUMENT_ID" \
  -H "Authorization: Bearer $MP_API_KEY" \
  -H "X-Namespace: $MP_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{ "metadata": { "status": "reviewed", "stale_field": null } }'
```

This sets `metadata.status` and removes `metadata.stale_field`. Every other metadata key
is untouched. A `PUT` behaves the same way, so a key missing from a `PUT` body stays.

### Where each key lands

A key inside `metadata` updates `metadata.<key>`. A key at the top level of the body
updates the document's own top-level field of that name. They are separate fields: a
field your collection copies onto the document (a passthrough field such as `brand_id`)
sits at the top level, so change it by sending it at the top level:

```bash theme={null}
curl -sS -X PATCH \
  "$MP_API_URL/v1/collections/$COLLECTION_ID/documents/$DOCUMENT_ID" \
  -H "Authorization: Bearer $MP_API_KEY" \
  -H "X-Namespace: $MP_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{ "brand_id": "brand-b" }'
```

`{"metadata": {"brand_id": "brand-b"}}` would instead add `metadata.brand_id` and leave
the top-level `brand_id` as it was. The response is the whole document, so you can see
which field changed.
`"metadata": null` returns a 422. To remove keys, name each one with a `null` value.

To update many documents at once, use `PATCH /v1/collections/{collection_id}/documents/bulk`.
Send `update_data` with the field-value pairs to apply, and `filters` to choose which
documents receive them. **Omitting `filters` updates every document in the collection.**

> [!WARNING]
>
> **Bulk update is asynchronous, and the response tells you nothing about the result.**
> The call returns `task_id` and `status: "PENDING"`, and `updated_count` is `null` on that
> enqueue response. The terminal status and the real `updated_count` land on the task
> record, so poll `GET /v1/tasks/{task_id}` before treating the update as applied.
>
> Reading `updated_count` off the immediate response gives you `null`, not zero.

> [!NOTE]
>
> **Object fields come back with their keys in alphabetical order.** A field written as `{"SKUs": ..., "source": ..., "Keywords": ...}` reads back from `documents/list` and retriever results as `{"Keywords": ..., "SKUs": ..., "source": ...}`. The values are unchanged. If you show an object's fields in a set order, keep that order in your application.

> [!NOTE]
>
> Updating metadata does **not** re-run extraction or change vectors — it only edits the stored payload. To change the embedding model, see [Migrate Embedding Models](https://docs.mixpeek.com/docs/processing/model-migration.md).

To change **access control** (not metadata), use the dedicated ACL endpoint `PATCH /v1/collections/{collection_id}/documents/{document_id}/acl` — see [Permissions](https://docs.mixpeek.com/docs/platform/permissions.md).

> [!NOTE]
>
> **Object metadata vs document metadata are separate.** The `PATCH` above edits a **document** (a processed, searchable record in a collection). To edit the source **object** in the bucket, use [`PATCH /v1/buckets/{bucket_id}/objects/{object_id}`](https://docs.mixpeek.com/docs/api-reference/bucket-objects/partially-update-object) and send the object's custom fields flat at the root of the body, for example `{"campaign_id": "camp_002"}`. Only the fields you send change. An object created with a `metadata` object keeps its fields there, and `{"metadata": {"tag": "new"}}` sets `metadata.tag` and leaves its other keys as they are. Editing one does not change the other, and re-processing an object regenerates its documents from the object's current state.

## Delete data

> [!WARNING]
>
> Deletes are permanent and some **cascade**. Read the cascade column before deleting — removing a bucket object or a collection also destroys derived documents.

| Delete | Endpoint | Cascades to |
| - | - | - |
| A document | `DELETE /v1/collections/{collection_id}/documents/{document_id}` | Just that document |
| Many documents | `DELETE /v1/collections/{collection_id}/documents/batch` | The documents you list |
| A bucket object | `DELETE /v1/buckets/{bucket_id}/objects/{object_id}` | **Hard-deletes every collection document derived from that object** |
| A collection | `DELETE /v1/collections/{collection_id}` | **All documents in the collection** |
| A namespace | `DELETE /v1/namespaces/{namespace_id}` | **Everything in the namespace** (buckets, collections, documents, retrievers) |

```bash theme={null}
# Delete a single document
curl -sS -X DELETE \
  "$MP_API_URL/v1/collections/$COLLECTION_ID/documents/$DOCUMENT_ID" \
  -H "Authorization: Bearer $MP_API_KEY" -H "X-Namespace: $MP_NAMESPACE"

# Delete a bucket object (also removes its derived documents)
curl -sS -X DELETE \
  "$MP_API_URL/v1/buckets/$BUCKET_ID/objects/$OBJECT_ID" \
  -H "Authorization: Bearer $MP_API_KEY" -H "X-Namespace: $MP_NAMESPACE"
```

> [!TIP]
>
> Deleting the **object** is the right move when you want the source asset *and* its derived documents gone. Deleting just the **document** leaves the source object in the bucket, so a re-process would recreate the document.

### Deleting many documents

`DELETE /v1/collections/{collection_id}/documents/batch` takes `document_ids` or
`filters`, and the two are mutually exclusive. Which one you send decides whether the
call is synchronous, so the response shape differs between them.

| Mode | Send | Response |
| - | - | - |
| Explicit IDs | `document_ids` | Synchronous. `deleted_count`, `failed_count` and per-document `results` are populated; `task_id` and `status` are `null` |
| Filter | `filters` | Asynchronous. `task_id` and `status: "PENDING"` are populated; `deleted_count` is `null` and `results` is an empty list |

> [!WARNING]
>
> **In filter mode, `deleted_count` is `null` rather than a count**, and `results` is empty
> because only counts are returned. Poll `GET /v1/tasks/{task_id}` for the terminal status
> and the final `deleted_count`. Code that reads `deleted_count` straight off the response
> sees `null` on a delete that is still running.

`reason` is optional on both modes and is recorded on the `DOCUMENT_BULK_SOFT_DELETED`
audit entry.

### Synced sources

If documents came from a [storage sync](https://docs.mixpeek.com/docs/platform/syncs.md), the sync's `reconcile.on_delete` is `true` by default, so deleting a file in the source (S3, Google Drive, etc.) automatically removes the corresponding object and its derived documents. Set `reconcile.on_delete` to `false` to keep Mixpeek objects when the source asset is deleted.

## Related

* [Documents](https://docs.mixpeek.com/docs/vector-store/documents.md) — document structure and payload
* [Syncs](https://docs.mixpeek.com/docs/platform/syncs.md) — source-deletion cascade (`on_delete`)
* [Ingest Data](https://docs.mixpeek.com/docs/platform/data-model.md) — objects, batches, collections


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