Hydra is now in beta|Get started free|Follow our journey on X.com

Metafields API
On this page

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)