# Add a custom field

> Declare a metafield definition and store a custom value on a product.

This guide adds a **custom field** to your catalog with [metafields](/api/product-management/metafields/): you declare the field once as a [metafield definition](/api/product-management/metafield-definitions/), then store a value for it on a product.

Custom fields are a two-step thing: the **definition** is the schema (a `key`, a data `type`, and any validations), and the **metafield** is the value of that definition on one record.

## Prerequisites

You need a **product** on an existing instance. If you don't have one, follow [Create your first product](/guides/create-your-first-product/) first.

As in that guide, the commands below use:

- the organization `id` - shown as `<org_id>`
- the instance `handle` (the tenant) - shown as `<tenant>`
- your product id - shown as `{productId}`

## Before you start

You need an OAuth 2.0 **bearer token** for a partner account. Sign in below: your token is dropped into every command on this page, and you can pick your organization and instance to fill `<org_id>` and `<tenant>` too. See [Authentication](/authentication/) for more.

## Steps

<Steps>

1. **Declare the field.**

   Create a [metafield definition](/api/product-management/metafield-definitions/) on the `products` owner type. Give it a `namespace`, a `key`, and a `type`. Capture the `@id` from the response - that's the definition you'll reference when setting values.

   ```bash
   curl -X POST 'https://<tenant>.product-management.flowkiwi.net/rest/api/metafield_definitions' \
     -H 'Authorization: Bearer {token}' \
     -H 'X-Flowkiwi-Organization-Id: <org_id>' \
     -H 'Content-Type: application/ld+json' \
     -d '{
       "name": "Care instructions",
       "description": "Washing and care guidance shown on the product page.",
       "namespace": "custom",
       "key": "care_instructions",
       "ownerType": "/rest/api/metafield_owner_types/products",
       "type": "/rest/api/metafield_definition_types/multi_line_text_field"
     }'
   ```

   ```json
   {
     "@id": "/rest/api/metafield_definitions/019afb01-1a2b-7c3d-8e4f-0a1b2c3d4e5f",
     "namespace": "custom",
     "key": "care_instructions",
     "type": "/rest/api/metafield_definition_types/multi_line_text_field"
   }
   ```

> **What can a type carry?**
>
> The validations a type accepts (and the constraints an owner type accepts) are not free-form. Read the [metafield definition type](/api/product-management/metafield-definition-types/) to see its `allowedValidations` before adding any - see [Type compatibility](/api/product-management/metafield-definitions/#type-compatibility).

2. **Set a value on a product.**

   Metafields are nested under their owner, so post the value to the product's metafields, referencing the `definition` from step 1.

   ```bash
   curl -X POST 'https://<tenant>.product-management.flowkiwi.net/rest/api/products/{productId}/metafields' \
     -H 'Authorization: Bearer {token}' \
     -H 'X-Flowkiwi-Organization-Id: <org_id>' \
     -H 'Content-Type: application/ld+json' \
     -d '{
       "value": "Machine wash cold at 30°C",
       "definition": "/rest/api/metafield_definitions/019afb01-1a2b-7c3d-8e4f-0a1b2c3d4e5f"
     }'
   ```

   The value is validated against the definition's `type` and `validations`; an invalid value is rejected with `422 Unprocessable Entity`.

3. **Read it back.**

   List the product's metafields - your custom value is now among them.

   ```bash
   curl 'https://<tenant>.product-management.flowkiwi.net/rest/api/products/{productId}/metafields' \
     -H 'Authorization: Bearer {token}' \
     -H 'X-Flowkiwi-Organization-Id: <org_id>' \
     -H 'Accept: application/ld+json'
   ```

</Steps>

## Next steps

- **Reuse the field.** The same definition applies to every product - set its value on as many products as you like.
- **Validate input.** Add a `validation` (such as `max_length`) to the definition so bad values are rejected up front.
- **Other owner types.** Define fields on `variants` and other [owner types](/api/product-management/metafield-owner-types/) the same way - just change `ownerType` and post under that owner.
