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

# Update Source Metadata

> Merge tenant metadata and additional metadata for one existing source without re-ingesting its content.

export const Field = ({name, type, required, recommended}) => {
  const label = required ? 'required' : recommended ? 'recommended' : null;
  const typeLabel = typeof type === 'string' ? type : null;
  const ariaParts = [name, typeLabel && `${typeLabel}`, label].filter(Boolean);
  return <span aria-label={ariaParts.join(', ')} className={label ? 'field-wrap has-field-tip' : 'field-wrap'} style={{
    position: 'relative',
    cursor: label ? 'default' : undefined
  }} tabIndex={label ? 0 : undefined}>
      <span className="field-name-row">
        <code>{name}</code>
        {required && <span className="field-req"> *</span>}
        {recommended && <span className="field-rec"> ●</span>}
      </span>
      {type && <span className="field-type">{type}</span>}
      {label && <span className="field-tip" role="tooltip">
          {label}
        </span>}
    </span>;
};

Use this endpoint when you know a source ID and need to update its metadata in place. It updates both the source row and indexed chunk metadata used by query/list filters.

```http theme={"dark"}
PATCH /context/sources/{source_id}/metadata
```

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X PATCH 'https://api.hydradb.com/context/sources/policy_main/metadata' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -H "Content-Type: application/json" \
    -d '{
      "database": "acme_corp",
      "collection": "team_docs",
      "tenant_metadata": {
        "department": "legal",
        "priority": 7
      },
      "additional_metadata": {
        "author": "Legal Team",
        "doc_version": 3
      }
    }'
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.patch(
      "https://api.hydradb.com/context/sources/policy_main/metadata",
      headers={
          "Authorization": f"Bearer {HYDRA_DB_API_KEY}",
          "API-Version": "2",
          "Content-Type": "application/json",
      },
      json={
          "database": "acme_corp",
          "collection": "team_docs",
          "tenant_metadata": {
              "department": "legal",
              "priority": 7,
          },
          "additional_metadata": {
              "author": "Legal Team",
              "doc_version": 3,
          },
      },
  )
  ```

  ```typescript TypeScript theme={"dark"}
  const response = await fetch("https://api.hydradb.com/context/sources/policy_main/metadata", {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${process.env.HYDRA_DB_API_KEY}`,
      "API-Version": "2",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      database: "acme_corp",
      collection: "team_docs",
      tenant_metadata: {
        department: "legal",
        priority: 7,
      },
      additional_metadata: {
        author: "Legal Team",
        doc_version: 3,
      },
    }),
  });
  ```
</RequestExample>

## Request

### Path parameters

| Name                                              | Description                                                                                                  |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| <Field name="source_id" type="string" required /> | Existing source ID to update. This is the `id` you supplied at ingest, or the source ID returned by HydraDB. |

### Body

| Name                                               | Description                                                                                                                        |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| <Field name="database" type="string" required />   | Owning database. (deprecated alias: `tenant_id`)                                                                                   |
| <Field name="collection" type="string" required /> | Collection that contains the source. This endpoint does not default it. (deprecated alias: `sub_tenant_id`)                        |
| <Field name="tenant_metadata" type="object" />     | Schema-backed metadata fields to merge into the source's `metadata`. Keys must satisfy the tenant metadata schema when one exists. |
| <Field name="additional_metadata" type="object" /> | Free-form metadata fields to merge into the source's `additional_metadata`.                                                        |

At least one of `tenant_metadata` or `additional_metadata` is required.

<Warning>
  This edit endpoint intentionally uses `tenant_metadata` for schema-backed source metadata. The shorter `metadata` field used by ingestion/list examples is not accepted in this PATCH body. `document_metadata` is also not accepted; use `additional_metadata`.
</Warning>

## Behavior

* The update is a **merge/upsert**:
  * keys present in the request are inserted or overwritten
  * keys omitted from the request are preserved
* The source must already exist. This endpoint does not create sources.
* The endpoint edits one source at a time. Bulk metadata edits are not supported.
* Updated metadata is visible to [`/query`](/api-reference/v2/endpoint/query) metadata filters and [`/context/list`](/api-reference/v2/endpoint/list-documents) filters.
* If an edited tenant metadata field has `enable_dense_embedding` or `enable_sparse_embedding`, HydraDB synchronously refreshes the relevant Milvus metadata search lane.
* If the edited fields are `enable_match`-only, the edit remains MongoDB-only and `milvus_sync_required` is `false`.

## Response

<ResponseExample>
  ```json Success theme={"dark"}
  {
    "success": true,
    "data": {
      "id": "policy_main",
      "tenant_id": "acme_corp",
      "sub_tenant_id": "team_docs",
      "updated": true,
      "tenant_metadata_keys": ["department", "priority"],
      "additional_metadata_keys": ["author", "doc_version"],
      "milvus_sync_required": false,
      "chunk_rows_matched": 4,
      "chunk_rows_modified": 4
    },
    "error": null,
    "meta": {
      "request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
      "latency_ms": 12.3
    }
  }
  ```

  ```json Dense or sparse metadata sync theme={"dark"}
  {
    "success": true,
    "data": {
      "id": "policy_main",
      "tenant_id": "acme_corp",
      "sub_tenant_id": "team_docs",
      "updated": true,
      "tenant_metadata_keys": ["summary_label"],
      "additional_metadata_keys": [],
      "milvus_sync_required": true,
      "milvus_synced": true,
      "milvus_rows_synced": 4,
      "chunk_rows_matched": 4,
      "chunk_rows_modified": 4
    },
    "error": null,
    "meta": {
      "request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
      "latency_ms": 28.9
    }
  }
  ```

  ```json Failure theme={"dark"}
  {
    "success": false,
    "data": null,
    "error": {
      "code": "BAD_REQUEST",
      "message": "invalid metadata edit: tenant_metadata.department must be of type VARCHAR"
    },
    "meta": {
      "request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
      "latency_ms": 4.8
    }
  }
  ```
</ResponseExample>

| Field                                                     | Description                                                                                |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| <Field name="id" type="string" />                         | Updated source ID.                                                                         |
| <Field name="tenant_id" type="string" />                  | Public tenant ID.                                                                          |
| <Field name="sub_tenant_id" type="string" />              | Sub-tenant that contained the source.                                                      |
| <Field name="updated" type="boolean" />                   | `true` when the source metadata was updated.                                               |
| <Field name="tenant_metadata_keys" type="string[]" />     | Tenant metadata keys included in the request.                                              |
| <Field name="additional_metadata_keys" type="string[]" /> | Additional metadata keys included in the request.                                          |
| <Field name="milvus_sync_required" type="boolean" />      | `true` when at least one changed tenant metadata field has dense/sparse embedding enabled. |
| <Field name="milvus_synced" type="boolean" />             | Present when sync was required. `true` means the sync completed.                           |
| <Field name="milvus_rows_synced" type="integer" />        | Number of chunk rows synced to Milvus when sync was required.                              |
| <Field name="chunk_rows_matched" type="integer" />        | Number of MongoDB chunk rows matched by the source update.                                 |
| <Field name="chunk_rows_modified" type="integer" />       | Number of MongoDB chunk rows modified by the source update.                                |

## Validation and errors

| Status | When it happens                                                                                                                                                                                                                                                |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Missing `tenant_id`, missing `sub_tenant_id`, empty metadata payload, `document_metadata` supplied, unknown tenant metadata key when a schema exists, wrong type, reserved key, over-size value, too-deep nesting, or `null` for a dense/sparse-enabled field. |
| `404`  | Source does not exist for the `(tenant_id, sub_tenant_id, source_id)` scope.                                                                                                                                                                                   |
| `500`  | Metadata was written to MongoDB but dense/sparse Milvus sync failed. Retry the same idempotent edit to converge.                                                                                                                                               |

## Related

* [Scoping using metadata](/essentials/v2/metadata)
* [Ingest Context](/api-reference/v2/endpoint/ingest-context)
* [List Context](/api-reference/v2/endpoint/list-documents)
* [Query](/api-reference/v2/endpoint/query)
