Metadata & External Correlation
Use metadata to attach custom fields to commerce objects and to correlate events with external systems (CRMs, fulfillment partners, affiliate networks, healthcare platforms, plan-management services, etc.). This guide covers which objects support custom metadata, how to read it back through the API and webhooks, and the canonical pattern for correlating an external identifier across a customer's full subscription lifecycle.
Supported Objects
The Metadata API lets you define custom fields ("definitions") on a fixed set of object types. The supported types are:
attribution— Marketing attributioncustomer— Customersdispute— Disputesline— Order line itemsorder— Ordersproduct— Productsvariant— Product variantsblog— Blog postspage— CMS pages
Define fields via metadataCreate. Each definition specifies the object type (from the list above), a key, a name, and a data type. Once defined, the field appears on the corresponding API responses and webhook payloads under that object's metadata block.
Subscriptions, carts, and several other resources are not directly metadata-managed. If you need to attach a custom field to a subscription (for example, an external plan_id that should travel with every rebill), use attribution.metadata instead — see Cross-Rebill Correlation via Attribution below.
Setting and Reading Metadata
After defining a field on a supported object type, set values on individual records via the resource's standard update endpoint. For example, to set order metadata:
{
"metadata": {
"external_order_id": "ext_abc123",
"fulfillment_priority": "rush"
}
}The values come back in:
- The corresponding GET endpoint (
GET /orders/{number}/) - The relevant
*.createdand*.updatedwebhooks for that object
Field validation (data type, allowed values) is enforced based on the definitions you registered.
Cross-Rebill Correlation via Attribution
A common integration pattern is: store an external system's identifier on a customer's subscription once, and receive it inline on every charge event for the lifetime of that subscription — without follow-up API calls.
For example: a merchant integrating with an external plan-management service (subscription plans, healthcare plans, affiliate plans, etc.) wants the plan_id to travel with every rebill order and every capture transaction so their fulfillment service can correlate back to the external system.
The pattern: store the identifier on the subscription's marketing attribution metadata. Every renewal order created by that subscription inherits the same attribution record, so attribution.metadata flows through automatically.
Step 1 — Define an attribution metadata field
Create a metadata definition with object: attribution to register the field shape:
{
"object": "attribution",
"key": "plan_id",
"name": "Plan ID",
"type": "string"
}Step 2 — Set the value on the subscription's attribution
Patch the subscription with attribution metadata:
{
"attribution": {
"metadata": {
"plan_id": "plan_abc123"
}
}
}Step 3 — Receive it inline on every charge event
The same attribution.metadata object is included in:
subscription.updatedpayloadsorder.createdpayloads — including every renewal order, because rebill order placement reuses the subscription's attribution recordtransaction.createdpayloads — for both initial captures and rebill captures
{
"event_type": "transaction.created",
"data": {
"type": "debit",
"amount": "29.99",
"subscription": {
"id": 12345,
"billing_cycle": 3
},
"attribution": {
"metadata": {
"plan_id": "plan_abc123"
},
"utm_source": "...",
"utm_campaign": "..."
}
}
}Set the value once when the subscription is created (or when the external system first issues an identifier), and your webhook receiver can read it back from data.attribution.metadata on every subsequent charge.
Why attribution and not a different field? attribution.metadata is the only metadata surface that (a) lives on the subscription, (b) is inherited by every renewal order automatically, and (c) is included inline on transaction.created payloads. Other approaches require either per-order writes (storing on order.metadata for each rebill) or a follow-up API call (storing on customer.metadata and fetching on every charge).
When to Use Which Surface
| Need | Use |
|---|---|
| Custom field on a single order (e.g., custom routing, gift message) | order.metadata |
| Custom field on a customer record, viewable in customer webhooks | customer.metadata |
| External ID that should travel with every charge for a subscription | attribution.metadata on the subscription |
| Per-line-item custom fields (e.g., engraving text, dosage instructions) | line.metadata |
| Custom catalog data (e.g., supplier SKU, regulatory codes) | product.metadata or variant.metadata |
| Dispute case notes / external reference | dispute.metadata |
For data that doesn't fit any of these — for example, cart-level data or session-level data — you'll need to handle it in your application layer; those resources are not part of the public Metadata API surface.