# Custom Metadata
URL: https://www.quiltt.dev/api/custom-metadata
Description: Discover how to extend Quiltt's core resources with custom metadata. Learn to add, update, and manage arbitrary data for Profiles, Connections, and more.
Navigation: api → custom-metadata
Tags: API
Content Length: 7k characters

Core resources in Quiltt can be easily extended with additional custom information, using the `metadata` field.

## Use Cases

The `metadata` field allows you to store arbitrary custom data in a structured manner. You can use this to store many types of static or dynamic information that may be useful to retrieve later. Below are some examples:

### Persist Static Data

- An internal ID or reference, such as the ID of the resource in your database
- An external identifier for a 3rd party system, like authentication or analytics
- A Profile's nickname or preferred pronoun

### Track Dynamic States

- When was the last time someone interacted with a Connection or Account in your app?
- Is an Account treated as "active" in your system?
- Should a Transaction be hidden in your UI?

## Supported Resources

The following resources currently expose a `metadata` field via corresponding [GraphQL mutations](https://www.quiltt.dev/api/graphql/mutations):

| Resource    | GraphQL Mutation    |
| ----------- | ------------------- |
| Profile     | `profileUpdate`     |
| Connection  | `connectionUpdate`  |
| Account     | `accountUpdate`     |
| Transaction | `transactionUpdate` |

Additionally, Profile `metadata` can also be managed using the below server-to-server endpoints:

API Endpoint - POST https://api.quiltt.io/v1/users/sessions:

API Endpoint - POST https://api.quiltt.io/v1/profiles:

API Endpoint - PATCH https://api.quiltt.io/v1/profiles/{profileId}:

## Usage Examples

The best way to interact with metadata is by using the GraphQL explorer in the [Quiltt Dashboard](https://dashboard.quiltt.dev), or [Quiltt Hub](https://quiltthub.com).

For this example, we'll assume we have a Profile named Quiltty, then add and remove some metadata.

### Adding Metadata

First we'll assign some internal identifiers to track via `metadata`.

#### GraphQL

GraphQLRequest:

Query:
```graphql
mutation {
  profileUpdate(
    input: {
      metadata: [internal_user_id: 12345,
        firebase_id: "Xk3D12aB4zO7QW5z8s9Y"]
    }
  ) {
    record [id
      metadata]
  }
}
```

  

Response:
```json
{
  "data": {
    "profileUpdate": {
      "record": {
        "id": "p_12vTuTMBAXZQM6zb7mjRml",
        "metadata": ["internal_user_id": 12345,
          "firebase_id": "Xk3D12aB4zO7QW5z8s9Y"]
      }
    }
  }
}
```

#### REST

Code Examples:

  ```sh
    curl --request PATCH \
      --url 'https://api.quiltt.io/v1/profiles/p_12vTuTMBAXZQM6zb7mjRml' \
      --header 'Authorization: Bearer <API_SECRET_KEY>' \
      --header 'Content-Type: application/json' \
      --data-raw '{
        "metadata": ["internal_user_id": 12345,
          "firebase_id": "Xk3D12aB4zO7QW5z8s9Y"]
      }'
    ```
  ```json
    {
      "id": "p_12vTuTMBAXZQM6zb7mjRml",
      "uuid": "018d1da5-d96f-7a1d-869e-7df60ce139b3",
      "metadata": ["internal_user_id": 12345,
        "firebase_id": "Xk3D12aB4zO7QW5z8s9Y"],
      "email": "quiltty@quiltt.dev",
      "phone": null,
      "name": "Quiltty",
      "names": null,
      "dateOfBirth": null,
      "address": null,
      "at": "2025-01-18T17:37:04Z"
    }
    ```

### Changing Metadata

Let's say we've learned that Quiltty's favorite color is purple. We can reflect that on the Profile by adding that data to `metadata`:

#### GraphQL

GraphQLRequest:

Query:
```graphql
mutation {
  profileUpdate(input: {metadata: [favoriteColor: "purple"]}) {
    record [id
      metadata]
  }
}
```

  

Response:
```json
{
  "data": {
    "profileUpdate": {
      "record": {
        "id": "p_12vTuTMBAXZQM6zb7mjRml",
        "metadata": ["internal_user_id": 12345,
          "firebase_id": "Xk3D12aB4zO7QW5z8s9Y",
          "favoriteColor": "purple"]
      }
    }
  }
}
```

#### REST

Code Examples:

  ```sh
    curl --request PATCH \
      --url 'https://api.quiltt.io/v1/profiles/p_12vTuTMBAXZQM6zb7mjRml' \
      --header 'Authorization: Bearer <API_SECRET_KEY>' \
      --header 'Content-Type: application/json' \
      --data-raw '{
        "metadata": ["favoriteColor": "purple"]
      }'
    ```
  ```json
    {
      "id": "p_12vTuTMBAXZQM6zb7mjRml",
      "uuid": "018d1da5-d96f-7a1d-869e-7df60ce139b3",
      "metadata": ["favoriteColor": "purple"],
      "email": "quiltty@quiltt.dev",
      "phone": null,
      "name": "Quiltty",
      "names": null,
      "dateOfBirth": null,
      "address": null,
      "at": "2025-01-18T17:37:04Z"
    }
    ```

Note that the existing `metadata` keys are not touched unless they're explicitly set in the request.

Now let's say we've migrated off of Firebase. To delete the `metadata` entry, we can simply set the key to `null`:

#### GraphQL

GraphQLRequest:

Query:
```graphql
mutation {
  profileUpdate(input: {metadata: [favoriteColor: null]}) {
    record [id
      metadata]
  }
}
```

  

Response:
```json
{
  "data": {
    "profileUpdate": {
      "record": {
        "id": "p_12vTuTMBAXZQM6zb7mjRml",
        "metadata": ["firebase_id": "Xk3D12aB4zO7QW5z8s9Y"]
      }
    }
  }
}
```

#### REST

Code Examples:

  ```sh
    curl --request PATCH \
      --url 'https://api.quiltt.io/v1/profiles/p_12vTuTMBAXZQM6zb7mjRml' \
      --header 'Authorization: Bearer <API_SECRET_KEY>' \
      --header 'Content-Type: application/json' \
      --data-raw '{
        "metadata": ["firebase_id": "Xk3D12aB4zO7QW5z8s9Y"]
      }'
    ```
  ```json
    {
      "id": "p_12vTuTMBAXZQM6zb7mjRml",
      "uuid": "018d1da5-d96f-7a1d-869e-7df60ce139b3",
      "metadata": ["firebase_id": "Xk3D12aB4zO7QW5z8s9Y"],
      "email": "quiltty@quiltt.dev",
      "phone": null,
      "name": "Quiltty",
      "names": null,
      "dateOfBirth": null,
      "address": null,
      "at": "2025-01-18T17:37:04Z"
    }
    ```

To clear `metadata` entirely, we can set all the defined keys to `null` or the entire metadata object to `null`.

#### GraphQL

GraphQLRequest:

Query:
```graphql
mutation {
  profileUpdate(input: [metadata: null]) {
    record [id
      metadata]
  }
}
```

  

Response:
```json
{
  "data": {
    "profileUpdate": {
      "record": ["id": "p_12vTuTMBAXZQM6zb7mjRml",
        "metadata": null]
    }
  }
}
```

#### REST

Code Examples:

  ```sh
    curl --request PATCH \
      --url 'https://api.quiltt.io/v1/profiles/p_12vTuTMBAXZQM6zb7mjRml' \
      --header 'Authorization: Bearer <API_SECRET_KEY>' \
      --header 'Content-Type: application/json' \
      --data-raw '["metadata": null]'
    ```
  ```json
    ["id": "p_12vTuTMBAXZQM6zb7mjRml",
      "uuid": "018d1da5-d96f-7a1d-869e-7df60ce139b3",
      "metadata": null,
      "email": "quiltty@quiltt.dev",
      "phone": null,
      "name": "Quiltty",
      "names": null,
      "dateOfBirth": null,
      "address": null,
      "at": "2025-01-18T17:37:04Z"]
    ```

### Filtering by Metadata

In GraphQL, you can filter records by the contents of the `metadata` field.

For example, here's how you can query Connections by an internal identifier you've written to a Connection's `metadata`.

GraphQLRequest:

Query:
```graphql
query FilterConnectionsByMetadata {
  connections(filter: { metadata: [internal_connection_id: "my_custom_id"] }) [id
    metadata]
}
```

  

Response:
```json
{
  "data": {
    "connections": [
      {
        "id": "conn_12tgD1WgzFgsy9fqKpW9b3",
        "metadata": ["internal_connection_id": "my_custom_id"]
      }
    ]
  }
}
```

Similarly, you can filter for records without any metadata by supplying `metadata: null` to the filter.

## Limitations

Custom metadata must be sent as a valid key-value JSON object, and must include at least 1 string key. There is a maximum capacity of 50 keys per record, with key names limited to 50 characters and values limited to 500 characters.

You should avoid storing any sensitive data that may contain 

PII

. in the `metadata` object. If you need to store sensitive data like emails, phone numbers or birthdays, use the dedicated fields on the Profile, which provide an additional level of encryption, as explained in the [Core Concepts](/get-started/core-concepts#profiles) guide.