> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Overwrite Document Metadata in Batches

PUT https://api.captain.dev/v3/collections/{collection_name}/documents/metadata/batch
Content-Type: application/json

Overwrite the `custom_metadata` object on up to 100 documents in one request. Each item behaves like [Overwrite Document Metadata](/reference/v3/document/metadata/replace). Returns 200 with one result per item, in order. Overwrite is destructive: omitted keys are removed and `{}` clears the target. Consider [copying the collection](/reference/collections/copy) first. Envelope, partial success, and `unknown` outcomes are covered in the [Batch Metadata & Relations](/guides/batch-writes) guide.

Reference: https://docs.runcaptain.com/reference/v3/document/metadata/batch/replace

## Request

### Path parameters

- `collection_name` (string, required)

### Body (application/json)

This endpoint expects a BatchDocumentMetadataRequestV3.

- `items` (list of BatchDocumentMetadataItemV3, required) — 1 to 100 items. The request body may not exceed 1 MiB of UTF-8 JSON.

## Response

### 200

Overwrite Document Metadata in Batches response.

- `results` (list of BatchDocumentMetadataResultV3, required) — One result per request item, in request order. Never empty for an accepted batch.

## Errors

### 400 Bad Request Error

Rejected before any write: malformed envelope, item count outside 1 to 100, duplicate `item_id` or targets, or a structural field error.

- `error` (BatchItemErrorV3, required)

### 401 Unauthorized Error

Missing or invalid authentication.

- `error` (string, required) — Error kind. `HTTP_ERROR` for errors raised by the route.
- `message` (string, required) — What went wrong.
- `path` (string, required) — The request path.
- `status_code` (integer, optional) — The HTTP status code.

### 403 Forbidden Error

API key cannot write to this collection.

- `error` (string, required) — Error kind. `HTTP_ERROR` for errors raised by the route.
- `message` (string, required) — What went wrong.
- `path` (string, required) — The request path.
- `status_code` (integer, optional) — The HTTP status code.

### 404 Not Found Error

Collection not found. A missing item target is reported inside `results[]`.

- `error` (string, required) — Error kind. `HTTP_ERROR` for errors raised by the route.
- `message` (string, required) — What went wrong.
- `path` (string, required) — The request path.
- `status_code` (integer, optional) — The HTTP status code.

### 413 Content Too Large Error

Request body larger than 1 MiB.

- `error` (BatchItemErrorV3, required)

## Types

### BatchDocumentMetadataItemV3

- `item_id` (string, required) — Non-empty string, unique within the request. Echoed on the matching result. Not an idempotency key.
- `document_id` (string, required) — A document ID returned by an indexing job or the document list. Filenames and guessed IDs are not accepted.
- `metadata` (map from string to any, required) — Custom metadata for this item. Reserved keys are rejected the same way the single-item endpoint rejects them.

### BatchDocumentMetadataResultV3

One entry per request item, in request order. Exactly one of `data` (status `succeeded`) or `error` (status `failed` or `unknown`) is present; a result never carries both or neither.

- `status`: `succeeded` (BatchDocumentMetadataSuccessV3)
  - `data` (DocumentMetadataResponseV3, required) — The same shape the single-item document metadata endpoints return, including `filterable`.
  - `http_status` (integer, required) — The status the matching single-item endpoint would have returned for this item.
  - `item_id` (string, required) — Echoed from the request item.
- `status`: `failed` (BatchDocumentMetadataFailureV3)
  - `error` (BatchItemErrorV3, required)
  - `http_status` (integer, required) — The status the matching single-item endpoint would have returned for this item.
  - `item_id` (string, required) — Echoed from the request item.
- `status`: `unknown` (BatchDocumentMetadataFailureV3)
  - `error` (BatchItemErrorV3, required)
  - `http_status` (integer, required) — The status the matching single-item endpoint would have returned for this item.
  - `item_id` (string, required) — Echoed from the request item.

### BatchItemErrorV3

- `code` (string, required) — Stable error code. Item-level codes are the ones the matching single-item endpoint uses for the same failure, plus `outcome_unknown` and `relation_identity_ambiguous`.
- `message` (string, required)

### DocumentMetadataResponseV3

Response for the document-metadata write endpoints (CAP-659).

- `document_id` (string, required)
- `custom_metadata` (map from string to any, optional)
- `filterable` (boolean, optional, default: false)
- `updated_at` (string, optional, nullable)

## Examples

**Request**

```json
{
  "items": [
    {
      "item_id": "update-1",
      "document_id": "doc-a",
      "metadata": {
        "review_status": "reviewed"
      }
    },
    {
      "item_id": "update-2",
      "document_id": "doc-b",
      "metadata": {
        "review_status": "pending"
      }
    }
  ]
}
```

**Response**

```json
{
  "results": [
    {
      "status": "succeeded",
      "data": {
        "document_id": "doc-a",
        "custom_metadata": {
          "review_status": "reviewed"
        },
        "filterable": true
      },
      "http_status": 200,
      "item_id": "update-1"
    },
    {
      "status": "failed",
      "error": {
        "code": "target_not_found",
        "message": "Target not found."
      },
      "http_status": 404,
      "item_id": "update-2"
    }
  ]
}
```

**SDK Code**

```python
import json
import requests

BASE_URL = "https://api.captain.dev"
API_KEY = "your_api_key"
COLLECTION_NAME = "my_documents"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

response = requests.put(
    f"{BASE_URL}/v3/collections/{COLLECTION_NAME}/documents/metadata/batch",
    headers=headers,
    json={
        "items": [
            {
                "item_id": "update-1",
                "document_id": "doc-a",
                "metadata": {
                    "review_status": "reviewed"
                }
            },
            {
                "item_id": "update-2",
                "document_id": "doc-b",
                "metadata": {
                    "review_status": "pending"
                }
            }
        ]
    },
    timeout=60.0
)

for result in response.json()["results"]:
    print(result["item_id"], result["status"], result["http_status"])
```

```typescript
const BASE_URL = "https://api.captain.dev";

const API_KEY = "your_api_key";

const collection_name = "my_documents";

const headers = {
  Authorization: `Bearer ${API_KEY}`,
  "Content-Type": "application/json",
};

const response = await fetch(`${BASE_URL}/v3/collections/${collection_name}/documents/metadata/batch`, {
  method: "PUT",
  headers,
  body: JSON.stringify({
    "items": [
      {
        "item_id": "update-1",
        "document_id": "doc-a",
        "metadata": {
          "review_status": "reviewed"
        }
      },
      {
        "item_id": "update-2",
        "document_id": "doc-b",
        "metadata": {
          "review_status": "pending"
        }
      }
    ]
  }),
});

const { results } = await response.json();
for (const result of results) {
  console.log(result.item_id, result.status, result.http_status);
}
```