---
title: "Metadata"
description: "Put your own key-value pairs, such as an order number, on objects; change or remove them."
url: https://docs.fluveo.com/start/metadata/
---

> Index of every page: https://docs.fluveo.com/llms.txt. Integrating Fluveo? Read https://docs.fluveo.com/agents/integrate.md first.

> Too long? This page with code in one language only: https://docs.fluveo.com/start/metadata.curl.md (cURL), https://docs.fluveo.com/start/metadata.node.md (Node.js), https://docs.fluveo.com/start/metadata.python.md (Python), https://docs.fluveo.com/start/metadata.php.md (PHP).

# Metadata

Put your own key-value pairs, such as an order number, on objects; change or remove them.

Most objects you create, such as a PaymentIntent, a Refund, a Customer or a Payout, carry a `metadata` map. Use it for your own references: an order number, your customer id, the name of the store a sale came from. Fluveo stores it and gives it back on every read and in every [event](https://docs.fluveo.com/webhooks.md). Fluveo never acts on it and never shows it to the buyer.

## Set metadata

Send each pair as `metadata[key]=value` when you create the object.

**Create a PaymentIntent with metadata**

cURL:

```bash
curl https://api.fluveo.com/v1/payment_intents \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: order-1042-create" \
  -d amount=2000 \
  -d currency=usd \
  -d "metadata[order_id]=1042" \
  -d "metadata[channel]=web"
```

Node.js:

```javascript
const response = await fetch("https://api.fluveo.com/v1/payment_intents", {
  method: "POST",
  headers: { Authorization: "Bearer sk_test_...", "Idempotency-Key": "order-1042-create" },
  body: new URLSearchParams({
    amount: "2000",
    currency: "usd",
    "metadata[order_id]": "1042",
    "metadata[channel]": "web",
  }),
});
console.log((await response.json()).metadata);
```

Python:

```python
import requests

response = requests.post(
    "https://api.fluveo.com/v1/payment_intents",
    headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": "order-1042-create"},
    data={
        "amount": 2000,
        "currency": "usd",
        "metadata[order_id]": "1042",
        "metadata[channel]": "web",
    },
)
print(response.json()["metadata"])
```

PHP:

```php
<?php
$ch = curl_init("https://api.fluveo.com/v1/payment_intents");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_...", "Idempotency-Key: order-1042-create"],
    CURLOPT_POSTFIELDS => http_build_query([
        "amount" => 2000,
        "currency" => "usd",
        "metadata" => ["order_id" => "1042", "channel" => "web"],
    ]),
]);
echo curl_exec($ch);
```

On a create, a pair with an empty value is not stored.

## Change or remove metadata

Send pairs on the object's update request, such as `POST /v1/payment_intents/{id}`. Each key you send changes only that key. The others stay as they are.

| You send | Result |
| --- | --- |
| `metadata[channel]=app` | `channel` becomes `app`; other keys stay. |
| `metadata[channel]=` (empty value) | `channel` is removed; other keys stay. |
| `metadata=` (empty, no brackets) | Every key is removed. |
| `metadata=` together with a `metadata[...]` pair | Refused with `400`. Send one or the other. |

## Limits

| Rule | Limit |
| --- | --- |
| Keys per object | at most 50 |
| Key length | 1 to 40 characters, without `[` or `]` |
| Value length | at most 500 characters |
| Types | keys and values are strings; turn numbers and dates into text yourself |
| Reserved prefix | a key that starts with `fluveo_`, in any letter case, is refused with `400` |

A request over a limit answers `400` with `param` `metadata` and a message that names the rule.

> **Keep personal data out of metadata:** Never put card numbers, security codes, passwords or more personal data than you need in metadata. It comes back on every read and in every event.
>
> A card number sent in metadata anyway is not refused. Fluveo stores it with each digit written X, in the value and in the key. A key that held one comes back with letters in place of its first X, such as `QhrTbBsJXXXXXXXX`. Sending that same key again changes the same entry.

## Test it

1. Create a test PaymentIntent with `metadata[order_id]=1042`. The answer shows it.
2. Update it with `metadata[order_id]=`. The key is gone.
3. Create one with `metadata[fluveo_order]=1`. You get `400`.

> **For AI agents:**
>
> metadata is a flat map of strings: at most 50 keys, keys 1 to 40 characters without brackets, values up to 500 characters. Never use keys starting with fluveo_. On update, an empty value deletes one key and metadata= deletes all; never send both forms together.

## Next

- [Versioning](https://docs.fluveo.com/start/versioning.md): The API version Fluveo serves.
- [Expanding responses](https://docs.fluveo.com/start/expand.md): Get related objects in the same answer.
