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

# Entity metadata

> Attach custom JSON metadata to Uphold entities like users, accounts, and transactions to extend them with your business data and external system mappings.

Metadata allows you to store custom, persistent data associated with various entities in the Uphold system. Each entity instance can have its own metadata as a JSON object with a flexible schema tailored to your integration needs.

## Use cases

Metadata enables you to extend Uphold entities with your own business data:

* **External system integration**: Map Uphold entities to your internal records using custom identifiers
* **Application state**: Store user preferences, feature flags, or configuration per entity
* **Analytics & tracking**: Add custom tags, cohort identifiers, or attribution parameters
* **Business logic**: Persist data needed for your workflows, compliance, or operational rules

## Working with metadata

All metadata operations are performed via dedicated endpoints for each entity type. The endpoints follow a consistent pattern:

* **Set metadata**: `PUT /<api>/<entity>/<entityId>/metadata` - Create or replace metadata
* **Get metadata**: `GET /<api>/<entity>/<entityId>/metadata` - Retrieve metadata
* **Update metadata**: `PATCH /<api>/<entity>/<entityId>/metadata` - Partially update metadata using JSON Patch
* **Delete metadata**: `DELETE /<api>/<entity>/<entityId>/metadata` - Remove all metadata

Where:

* `<api>` is the API name (e.g., `core`)
* `<entity>` is the entity type supported within the `<api>` (e.g., `users`, `accounts`)
* `<entityId>` is the unique identifier of the specific entity instance (e.g., user ID, account ID)

For each API that supports metadata, refer to the respective documentation to see the list of supported entities.

### Creating metadata

**Option 1: During entity creation**

Include a `metadata` field when creating entities. Here's an example of creating a user with metadata:

```json theme={null}
POST /core/users
{
  "email": "john.doe@example.com",
  "termsOfService": "general-gb-fca",
  "primaryCitizenship": "GB",
  "address": {
    "country": "GB",
    "subdivision": "GB-MAN"
  },
  "partnerOnboardedAt": "2025-02-01T00:00:00Z",
  "metadata": {
    "externalId": "usr_12345",
    "tier": "premium"
  }
}
```

<Note>
  If metadata creation fails, the entity is still created successfully. The response will include an `errors.metadata` property. See [Error handling](#errors-during-entity-creation) for details.
</Note>

**Option 2: Using the dedicated endpoint**

Use the **Set metadata** endpoint after entity creation. Here's an example of adding metadata to the authenticated user:

```json theme={null}
PUT /core/users/me/metadata
{
  "externalId": "usr_12345",
  "tier": "premium"
}
```

### Retrieving metadata

To fetch the metadata for an entity, use the **Get metadata** endpoint. Here's an example of retrieving metadata for the authenticated user:

```
GET /core/users/me/metadata
```

Response:

```json theme={null}
{
  "metadata": {
    "externalId": "usr_12345",
    "tier": "premium"
  }
}
```

### Updating metadata

**Option 1: Full replacement**

To completely replace the existing metadata, use the **Set metadata** endpoint. Here's an example of updating the metadata for the authenticated user:

```json theme={null}
PUT /core/users/me/metadata
{
  "externalId": "usr_12345",
  "tier": "enterprise"
}
```

**Option 2: Partial update**

To modify specific properties, use the **Update metadata** endpoint with a [JSON Patch](http://jsonpatch.com/) payload. Here's an example of partially updating the metadata for the authenticated user:

```json theme={null}
PATCH /core/users/me/metadata
[
  { "op": "replace", "path": "/tier", "value": "enterprise" },
  { "op": "add", "path": "/region", "value": "us-west" }
]
```

### Deleting metadata

To remove all metadata associated with an entity, use the **Delete metadata** endpoint. Here's an example of deleting the metadata for the authenticated user:

```
DELETE /core/users/me/metadata
```

## Error handling

### Size limit exceeded

Metadata payloads have a maximum size of **1024 Unicode characters**. If the payload exceeds this limit, a `413 Payload Too Large` error is returned:

```json theme={null}
{
  "code": "content_too_large",
  "message": "The entity metadata size is greater than maximum size limit",
  "details": {
    "threshold": {
      "unit": "characters",
      "limit": "1024"
    }
  }
}
```

### Errors during entity creation

When creating an entity with metadata, if the metadata operation fails, **the entity is still created successfully**. The response includes an `errors.metadata` property describing the issue:

```json theme={null}
{
  "user": {
    "id": "cd21b26d-35d2-408a-9201-b8fdbef7a604",
    "email": "john.doe@example.com"
    // ... other user properties ...
  },
  "errors": {
    "metadata": {
      "code": "content_too_large",
      "message": "The entity metadata size is greater than maximum size limit",
      "details": {
        "threshold": {
          "unit": "characters",
          "limit": "1024"
        }
      }
    }
  }
}
```

This ensures that entity creation is not blocked by metadata issues. You can add the metadata afterward using the **Set metadata** endpoint.

## HTTP conditional requests

Metadata endpoints support standard HTTP conditional request headers for concurrency control and efficient caching.
These headers are optional but recommended to prevent conflicts and optimize bandwidth.

**`ETag` response header**:

This header is included in responses to represent the current revision of the metadata.

**`If-Match` request header**:

When updating (via PUT or PATCH) or deleting metadata, include this header with the `ETag` value from a previous response to ensure you're modifying the expected version. If the `ETag` does not match the current version, a `412 Precondition Failed` error is returned, preventing accidental overwrites.

**`If-None-Match` request header**:

When retrieving metadata, include this header with the `ETag` value from a previous response. If the metadata has not changed, a `304 Not Modified` response is returned, saving bandwidth.

Additionally, when creating metadata and you want to ensure none already exists, you can use the `If-None-Match` header with a value of `*`. If metadata already exists, a `412 Precondition Failed` error will be returned.
