On this page
- Relationship to metadata
- Endpoints — Definitions
- Endpoints — Values
- List definitions
- Query parameters
- Request
- Response 200
- Create a definition
- Request body
- Request
- Response 201
- Error 409 - duplicate slug
- Update a definition
- Request body
- Request
- Response 200
- Archive a definition
- Request
- Response 204
- Reorder definitions
- Request body
- Request
- Response 200
- List values
- Request
- Response 200
- Batch set values
- Request body
- Request
- Response 200
- Set a single value
- Request body
- Request
- Response 200
- Clear a value
- Request
- Response 204
- Expand support
- Supported value types
- Text types
- Number types
- Date types
- Other types
- Media types
- Reference types
- List types
- Measurement units
- The definition object
- The value object
Metafields
Metafields are typed custom fields that merchants define and attach to existing resources (products, variants, customers, collections, orders). Each metafield has a definition (type, label, slug, validation rules) and per-resource values.
Metafield definitions are store-wide configuration — they are not filtered by test/live mode. The same definitions apply to both test and live data. Only metafield values are scoped to test or live mode via the X-Test-Mode header or API key prefix.
Metafields require the Custom Data extension to be enabled. Definition management works regardless of the extension toggle (so merchants can set up fields before enabling), but value operations require the extension to be active.
Base URL: https://api.hydrajs.dev
Relationship to metadata
Hydra resources also have a metadata JSONB field — a simple key-value store for developer/integration use (like Stripe’s metadata). Metafields are the merchant-facing, typed, validated layer with admin UI and storefront visibility control. Both coexist on the same resources.
Endpoints — Definitions
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/store/metafields |
Secret | List definitions |
POST |
/v1/store/metafields |
Secret | Create a definition |
PATCH |
/v1/store/metafields/{owner_type}/{slug} |
Secret | Update a definition |
DELETE |
/v1/store/metafields/{owner_type}/{slug} |
Secret | Archive a definition |
PUT |
/v1/store/metafields/{owner_type}/reorder |
Secret | Reorder definitions |
Endpoints — Values
These endpoints exist on every resource that supports metafields. Replace :resource with products, variants, collections, customers, or orders.
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/{resource}/{id}/metafields |
Publishable | List values |
PUT |
/v1/{resource}/{id}/metafields |
Secret | Batch set values |
PUT |
/v1/{resource}/{id}/metafields/{slug} |
Secret | Set a single value |
DELETE |
/v1/{resource}/{id}/metafields/{slug} |
Secret | Clear a value |
List definitions
GET /v1/store/metafields
Returns all active (non-archived) metafield definitions for the store.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
owner_type |
string | - | Filter by owner type: product, variant, customer, collection, order |
Request
curl https://api.hydrajs.dev/v1/store/metafields?owner_type=product \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": [
{
"id": "mfd_abc123def456ghij",
"key": "mf_1",
"slug": "care_instructions",
"label": "Care Instructions",
"description": "Washing and drying instructions",
"owner_type": "product",
"value_type": "multi_line_text",
"choices": null,
"position": 0,
"required": false,
"storefront_visible": true,
"archived": false,
"created_at": "2026-08-22T10:00:00Z",
"updated_at": "2026-08-22T10:00:00Z"
}
]
}
ℹNo pagination
Definitions are returned as a flat list — a store will never have enough definitions to warrant pagination.
Create a definition
POST /v1/store/metafields
Creates a new metafield definition. The value_type and owner_type are locked after creation and cannot be changed.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
label |
string | Yes | Display name (1–100 chars) |
slug |
string | No | API identifier (1–50 chars, ^[a-z0-9][a-z0-9_-]*$). Auto-generated from label if omitted |
description |
string | No | Helper text (max 255 chars) |
owner_type |
string | Yes | Resource type: product, variant, customer, collection, order |
value_type |
string | Yes | Value type (see supported types below) |
choices |
string[] | No | Predefined allowed values (max 100). Only for single_line_text, integer, list.single_line_text, list.integer |
position |
integer | No | Display order (0-indexed). Auto-assigned to end if omitted |
required |
boolean | No | Default false |
storefront_visible |
boolean | No | Default true |
Request
curl -X POST https://api.hydrajs.dev/v1/store/metafields \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "Care Instructions",
"owner_type": "product",
"value_type": "multi_line_text",
"description": "Washing and drying instructions"
}'
Response 201
{
"data": {
"id": "mfd_abc123def456ghij",
"key": "mf_1",
"slug": "care_instructions",
"label": "Care Instructions",
"description": "Washing and drying instructions",
"owner_type": "product",
"value_type": "multi_line_text",
"choices": null,
"position": 0,
"required": false,
"storefront_visible": true,
"archived": false,
"created_at": "2026-08-22T10:00:00Z",
"updated_at": "2026-08-22T10:00:00Z"
}
}
Error 409 - duplicate slug
{
"error": {
"code": "conflict",
"message": "A metafield with slug \"care_instructions\" already exists for owner type \"product\"."
}
}
Update a definition
PATCH /v1/store/metafields/{owner_type}/{slug}
Updates label, slug, description, choices, required, or storefront visibility. Cannot change owner_type or value_type.
Request body
All fields optional.
| Field | Type | Description |
|---|---|---|
label |
string | New display name (1–100 chars) |
slug |
string | New API identifier (1–50 chars) |
description |
string | null | Helper text. Send null to clear |
choices |
string[] | null | Predefined values. Send null to clear |
required |
boolean | Required flag |
storefront_visible |
boolean | Storefront visibility |
archived |
boolean | Set false to restore an archived definition |
Request
curl -X PATCH https://api.hydrajs.dev/v1/store/metafields/product/care_instructions \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "Washing Instructions", "required": true}'
Response 200
Updated definition object.
⚠Un-archiving
When restoring an archived definition, if its original slug has been reused by a new definition, the restore fails with 409. Provide a new slug in the same request: {"archived": false, "slug": "care_instructions_v2"}.
Archive a definition
DELETE /v1/store/metafields/{owner_type}/{slug}
Archives the definition. Values are preserved but become invisible in the admin and API. The slug is freed for reuse.
Request
curl -X DELETE https://api.hydrajs.dev/v1/store/metafields/product/care_instructions \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 204
Empty body.
Reorder definitions
PUT /v1/store/metafields/{owner_type}/reorder
Sets the display order of definitions for a given owner type. All active (non-archived) definition IDs for the owner type must be included.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
order |
string[] | Yes | Array of definition IDs in desired order |
Request
curl -X PUT https://api.hydrajs.dev/v1/store/metafields/product/reorder \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"order": ["mfd_abc123", "mfd_def456", "mfd_ghi789"]}'
Response 200
Full list of definitions for the owner type, sorted by new position.
List values
GET /v1/products/{id}/metafields
Returns all metafield values for a resource, keyed by slug. Publishable keys only see values where the definition has storefront_visible: true.
Request
curl https://api.hydrajs.dev/v1/products/prod_abc123/metafields \
-H "Authorization: Bearer pk_live_YOUR_KEY"
Response 200
{
"data": {
"care_instructions": {
"slug": "care_instructions",
"label": "Care Instructions",
"type": "multi_line_text",
"choices": null,
"value": "Machine wash cold, tumble dry low"
},
"is_organic": {
"slug": "is_organic",
"label": "Organic",
"type": "boolean",
"choices": null,
"value": true
}
}
}
ℹMap format
Unlike other expanded fields (variants, images), metafields return an object keyed by slug rather
than an array. This is intentional — metafields are accessed by key
(product.metafields.care_instructions.value), not iterated by index.
Returns {} if the Custom Data extension is not enabled or no values exist.
Batch set values
PUT /v1/products/{id}/metafields
Sets multiple metafield values in one request. Only provided keys are affected — omitted keys retain their current values. Send null to clear a field.
Request body
A JSON object with slugs as keys and values matching each field’s type. Send null to clear a value.
Request
curl -X PUT https://api.hydrajs.dev/v1/products/prod_abc123/metafields \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"care_instructions": "Machine wash cold, tumble dry low",
"is_organic": true,
"fabric_composition": null
}'
Response 200
Full metafields object (same shape as GET).
⚠Atomic validation
If any value fails type validation, the entire batch is rejected — no partial writes. Fix the invalid value and retry.
Set a single value
PUT /v1/products/{id}/metafields/{slug}
Sets a single metafield value. Creates or updates the value row.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
value |
varies | Yes | Value matching the definition’s value_type |
Request
curl -X PUT https://api.hydrajs.dev/v1/products/prod_abc123/metafields/care_instructions \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"value": "Hand wash only"}'
Response 200
{
"data": {
"slug": "care_instructions",
"label": "Care Instructions",
"type": "multi_line_text",
"choices": null,
"value": "Hand wash only"
}
}
Clear a value
DELETE /v1/products/{id}/metafields/{slug}
Deletes the value for the given slug. Does not affect the definition.
Request
curl -X DELETE https://api.hydrajs.dev/v1/products/prod_abc123/metafields/care_instructions \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 204
Empty body.
Expand support
Add ?expand=metafields to any resource that supports metafields to inline values in the response.
curl https://api.hydrajs.dev/v1/products/prod_abc123?expand=metafields \
-H "Authorization: Bearer pk_live_YOUR_KEY"
{
"data": {
"id": "prod_abc123",
"title": "Cotton T-Shirt",
"metafields": {
"care_instructions": {
"slug": "care_instructions",
"label": "Care Instructions",
"type": "multi_line_text",
"choices": null,
"value": "Machine wash cold, tumble dry low"
}
}
}
}
Publishable keys only see storefront_visible metafields. Returns {} if extension not enabled.
Supported value types
Text types
| Type | Storage | Validation |
|---|---|---|
single_line_text |
string | Max 500 chars, no newlines. Supports choices |
multi_line_text |
string | Max 5,000 chars |
email |
string | Valid email format, max 254 chars |
Number types
| Type | Storage | Validation |
|---|---|---|
integer |
number | Whole number. Supports choices |
decimal |
number | Up to 2 decimal places |
rating |
number | Integer 1–5 |
measurement |
object | {"value": 500, "unit": "g"} — number + valid unit from catalog |
Date types
| Type | Storage | Validation |
|---|---|---|
date |
string | ISO date YYYY-MM-DD |
datetime |
string | ISO 8601 with timezone |
Other types
| Type | Storage | Validation |
|---|---|---|
url |
string | Valid URL (http/https) |
boolean |
boolean | true or false |
color |
string | 6-digit hex with # prefix (#FF5733) |
Media types
| Type | Storage | Validation |
|---|---|---|
image_reference |
string | Image ID (img_...) |
file_reference |
string | File ID (file_...) |
video_reference |
string | File ID (file_...), must be video MIME type |
Reference types
| Type | Storage | Validation |
|---|---|---|
product_reference |
string | Product ID (prod_...), must exist |
variant_reference |
string | Variant ID (var_...), must exist |
collection_reference |
string | Collection ID (col_...), must exist |
customer_reference |
string | Customer ID (cus_...), must exist |
order_reference |
string | Order ID (ord_...), must exist |
List types
Any base type except boolean, multi_line_text, rating, and measurement can be made into a list by prefixing with list. (e.g., list.single_line_text, list.integer). List values are JSON arrays with max 50 items. Each item is validated individually.
{
"materials": ["Cotton", "Polyester", "Elastane"],
"certifications": ["GOTS", "OEKO-TEX"]
}
Measurement units
| Category | Units |
|---|---|
| Weight | kg, g, lb, oz |
| Length | m, cm, mm, in, ft |
| Volume | L, mL, fl_oz, gal |
The definition object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: mfd_) |
key |
string | Internal key (mf_1, mf_2, …) — immutable |
slug |
string | API identifier — changeable |
label |
string | Display name |
description |
string | null | Helper text |
owner_type |
string | Resource type this field applies to |
value_type |
string | Value type (locked after creation) |
choices |
string[] | null | Predefined allowed values |
position |
integer | Display order (0-indexed) |
required |
boolean | Whether the field is required |
storefront_visible |
boolean | Whether publishable keys can read this field |
archived |
boolean | Whether the definition is archived |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |
The value object
| Field | Type | Description |
|---|---|---|
slug |
string | Definition slug |
label |
string | Definition display name |
type |
string | Value type |
choices |
string[] | null | Predefined choices (if set on definition) |
value |
varies | Deserialized value (string, number, boolean, object, or array depending on type) |