> ## Documentation Index
> Fetch the complete documentation index at: https://cloudinary.com/documentation/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured metadata


## Overview

Cloudinary structured metadata allows you to define typed fields for media assets, populate them with values programmatically or via the [Media Library](dam_manage_metadata#setting_structured_metadata_values), and perform searches on them. You can also add validation rules, set default values, and define fields as mandatory.

A metadata field is a custom, typed field (key) for storing user defined data (value) with a media asset. 

> **NOTE**: Cloudinary product environments are limited to a maximum of 100 structured metadata fields each. After reaching the maximum, you must disable one or more existing fields in order to add a new one.

This page explains the [Metadata methods](admin_api#metadata_methods) for creating and managing structured metadata fields, as well as the [Metadata field structure](admin_api#metadata_field_structure) and how to structure field validation and list (datasource) values.

> **TIP**:
>
> :title=Tips

> * You can create and manage structured metadata fields from the **Manage Structured Metadata** page in the Cloudinary Console.  

> * You can return to the same page and confirm that the structured metadata fields you created or modified programmatically appear in the list as expected.
> For details, see [Managing structured metadata fields](media_library_for_developers#managing_structured_metadata_fields) on the _Media Library for Developers_ page.

> **NOTE**: You can set up dependencies and hierarchical relationships between structured metadata fields and field options using the [Conditional metadata rules API](conditional_metadata_rules_api).

## Quick example

Add a new mandatory metadata `set` (multi-select) field with an external_id of 'color_id', labeled 'Colors', and with 4 available colors: red, green, blue and yellow, where red and green are the default values:

```multi
|curl
curl \
  -H "Content-Type: application/json" \
  -d '{          
    "external_id": "color_id",
    "label": "Colors",
    "type": "set" ,
    "mandatory": "true",
    "default_value": ["color1","color2"],
    "datasource": {
      "values": [
        {"external_id": "color1", "value": "red"},
        {"external_id": "color2", "value": "green"},
        {"external_id": "color3", "value": "blue"},
        {"external_id": "color4", "value": "yellow"}
      ]
    }
  }' \  
  -X POST \
  https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<cloud_name>/metadata_fields

|ruby
Cloudinary::Api.add_metadata_field({          
  :"external_id" => "color_id",
  :"label" => "Colors",
  :"type" => "set" ,
  :"mandatory" => "true",
  :"default_value" => ["color1","color2"],
  :"datasource" => {
    :"values" => [
      {:"external_id" => "color1", :"value" => "red"},
      {:"external_id" => "color2", :"value" => "green"},
      {:"external_id" => "color3", :"value" => "blue"},
      {:"external_id" => "color4", :"value" => "yellow"}
    ]
  }
})

|php_2
use Cloudinary\Api\Metadata\SetMetadataField;

$datasourceValues = [
    ["external_id" => "color1", "value" => "red"],
    ["external_id" => "color2", "value" => "green"],
    ["external_id" => "color3", "value" => "blue"],
    ["external_id" => "color4", "value" => "yellow"],
];
$setMetadataField = new SetMetadataField("color_id", $datasourceValues);
$setMetadataField->setLabel("Colors");
$setMetadataField->setMandatory(true);
$setMetadataField->setDefaultValue(["color1", "color2"]);
$api->addMetadataField($setMetadataField);

|python
cloudinary.api.add_metadata_field({          
  "external_id": "color_id",
  "label": "Colors",
  "type": "set" ,
  "mandatory": True,
  "default_value": ["color1","color2"],
  "datasource": {
    "values": [
      {"external_id": "color1", "value": "red"},
      {"external_id": "color2", "value": "green"},
      {"external_id": "color3", "value": "blue"},
      {"external_id": "color4", "value": "yellow"}
    ]
  }
})

|nodejs
cloudinary.v2.api
.add_metadata_field({          
  "external_id": "color_id",
  "label": "Colors",
  "type": "set" ,
  "mandatory": "true",
  "default_value": ["color1","color2"],
  "datasource": {
    "values": [
      {"external_id": "color1", "value": "red"},
      {"external_id": "color2", "value": "green"},
      {"external_id": "color3", "value": "blue"},
      {"external_id": "color4", "value": "yellow"}
    ]
  }
})
.then(result=>console.log(result));

|java
SetMetadataField setField = new SetMetadataField();
setField.setExternalId("color_id");
setField.setLabel("Colors");
setField.setMandatory(true);
setField.setDefaultValue(Arrays.asList("color1", "color2"));
setField.setDataSource(new MetadataDataSource(Arrays.asList(
  new Entry("color1", "red"),
  new Entry("color2", "green"),
  new Entry("color3", "blue"),
  new Entry("color4", "yellow")
)));
api.addMetadataField(setField);


|csharp
var metadataFieldCreateParams = new SetMetadataFieldCreateParams("color_id"){
  Label = "Colors",
  Mandatory = true,
  DefaultValue = new List<string>{"color1" ,"color2"},
  DataSource = new MetadataDataSourceParams(new List<EntryParams>{
    new EntryParams("color1", "red"),
    new EntryParams("color2", "green"),
    new EntryParams("color3", "blue"),
    new EntryParams("color4", "yellow")})
};
cloudinary.AddMetadataField(metadataFieldCreateParams);

|go
resp, err := cld.Admin.AddMetadataField(ctx, metadata.Field{
	Type:         metadata.SetFieldType,
	ExternalID:   "color_id",
	Label:        "Colors",
	Mandatory:    true,
	DefaultValue: []string{"color1", "color2"},
	DataSource: metadata.DataSource{
		Values: []metadata.DataSourceValue{
			{
				ExternalID: "color1",
				Value:      "red",
				State:      "active",
			},
			{
				ExternalID: "color2",
				Value:      "green",
				State:      "active",
			},
			{
				ExternalID: "color3",
				Value:      "blue",
				State:      "active",
			},
			{
				ExternalID: "color4",
				Value:      "yellow",
				State:      "active",
			},
		},
	}})

|cli
cld admin add_metadata_field `{"external_id": "color_id", "label": "Colors", "type": "set", "mandatory": "true", "default_value": ["color1","color2"], "datasource": {"values": [{"external_id": "color1", "value": "red"}, {"external_id": "color2", "value": "green"}, {"external_id": "color3", "value": "blue"}, {"external_id": "color4", "value": "yellow"}]}}`
```
> **NOTE**: If running the CLI command on Windows, you need to escape the double quotes within the curly braces using either `\` or `"`, for example, `\"text\"` or `""text""`.
## Metadata API methods

The Metadata methods enable you to manage the metadata fields available for your product environment. 

The table below provides a quick summary of the methods available for the Admin API `metadata_fields` endpoint. See the [Metadata](admin_api#metadata_fields) reference documentation for more information on the following Metadata methods, as well as detailed information on the [Metadata field structure](admin_api#metadata_field_structure), including how to work with field validation and list (datasource) values.

> **NOTE**: These methods are part of the rate-limited [Admin API](admin_api), and share the same [usage limits](admin_api#usage_limits). See that documentation for more information on [pagination](admin_api#pagination) and [error handling](admin_api#error_handling).

Method | Description
---|---
GET<code class="code-method">/metadata\_fields | [Lists all metadata field definitions.](admin_api#get_metadata_fields)
GET<code class="code-method">/metadata\_fields/:external\_id | [Returns a single metadata field definition by external ID.](admin_api#get_a_metadata_field_by_external_id)
POST<code class="code-method">/metadata\_fields | [Creates a new metadata field definition.](admin_api#create_a_metadata_field)
POST<code class="code-method">/metadata\_fields/datasource/search | [Searches for datasource values across all metadata fields.](admin_api#search_metadata_field_datasource)
POST<code class="code-method">/metadata\_fields/:external\_id/datasource\_restore | [Restores entries in a metadata field datasource.](admin_api#restore_entries_in_a_metadata_field_datasource)
POST<code class="code-method">/metadata\_fields/:external\_id/datasource/order | [Order a metadata field datasource.](admin_api#order_a_metadata_field_datasource)
PUT<code class="code-method">/metadata\_fields/:external\_id | [Updates a metadata field definition by external ID.](admin_api#update_a_metadata_field_by_external_id)  
PUT<code class="code-method">/metadata\_fields/:external\_id/datasource | [Updates a metadata field datasource by external ID.](admin_api#update_a_metadata_field_datasource) 
DELETE<code class="code-method">/metadata\_fields/:external\_id | [Deletes a metadata field by external ID.](admin_api#delete_a_metadata_field_by_external_id)
DELETE<code class="code-method">/metadata\_fields/:external\_id/datasource | [Deletes entries in a metadata field datasource for a specified metadata field definition.](admin_api#delete_entries_in_a_metadata_field_datasource)

## Metadata API field structure

```json
{
  "external_id": <string>,
  "type": <field_type_enum>,
  "label": <string>,
  "mandatory": <boolean>,
  "restrictions": <restrictions_object>,
  "default_value": <field_type_value>,
  "validation": <validation_object>,
  "datasource": <datasource_object>  //enum and set types
}
```

> **NOTE**: For details on all the parameters, see the [Metadata field structure](admin_api#metadata_field_structure) reference.

### Validating data 

The `validation` parameter defines a validation object with the logic to apply when a value is entered for the field, via the [metadata](image_upload_api_reference#metadata), [upload](image_upload_api_reference#upload), [explicit](image_upload_api_reference#explicit) or [update resource](admin_api#get_details_of_a_single_resource_by_public_id) methods, or via the [Media Library](dam_manage_metadata#setting_custom_metadata_values). The boolean validations also allow for combinations of more than one rule. 

> **NOTE**: For details on all the parameters, see the [Validating data](admin_api#validating_data) reference.

**Example - Numeric range validation:**

```json
"validation":{
	"type":  "and"
	"rules": [{ 
		"type": "greater_than",
		"value": 10,
		"equals": true
	},
	{ 
		"type": "less_than",
		"value": 50,
		"equals": true
	}]
}
```

**Example - String regex validation:**

Regular expression validation for string fields ensures data follows specific patterns. This is particularly useful for fields used in integrations or that require consistent formatting.

```json
"validation": {
  "type": "strregex",
  "regex": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
}
```

Common use cases include validating email addresses, UUIDs, SKU codes, URL slugs, and other formatted identifiers. See the [strregex validation](admin_api#strregex_validation) reference for more examples and patterns.

### Datasource values

The `datasource` parameter is relevant for fields where the selected values must come from a predefined list of values (`enum` or `set` type fields). The parameter contains the `values` property, which defines the values for the `enum` or `set` list. Up to 3000 values can be defined for a list.

```json
{
	"values": [ <datasource_entry>, <datasource_entry>, … ]
}
```

> **NOTE**: For details on all the parameters, see the [Datasource values](admin_api#datasource_values) reference.

For example:

```json
"datasource": {
    "values": [{
    	"external_id": "color1", 
		"value": "red"
	},
    {	
    	"external_id": "color2", 
    	"value": "green"
    },
    {
    	"external_id": "color3", 
    	"value": "blue"
    },
    {
    	"external_id": "color4", 
    	"value": "yellow"
    }]
}
```

## Monitoring metadata changes using a notification URL

You can use [Cloudinary notifications](notifications#global_notification_urls) to monitor for changes to the structured metadata on your media assets, including structured metadata that has been added or removed via API or the Cloudinary Console UI. 

To capture these changes, add a [Notification URL](notifications#global_notification_urls) triggered by the 'Resource metadata changed' Notification Type in the [Webhook Notifications](https://console.cloudinary.com/app/settings/webhooks) page of your Console Settings. The notification sent will specify `resource_metadata_changed` as the `notification_type`, and include information about which resource was changed, the source of the change (UI or API), and whether structured metadata was added, removed, or updated. For example:

```json
{
  "notification_type": "resource_metadata_changed",
  "source": "api",
  "resources": {
    "jeans-1421398-1279x852_srghta": {
      "previous_metadata": {},
      "new_metadata": {
        "j8bcgcecnzrpitxo7gxh": "Levis"
      },
      "asset_id": "ede59e6d3befdc65a8adc2f381c0f96f",
      "resource_type": "image",
      "type": "upload"
    }
  },
  "notification_context": {
    "triggered_at": "2022-11-17T09:07:50.766353Z",
    "triggered_by": {
      "source": "api",
      "id": "45645295117726"
    }
  }
}
```

See the documentation on [Notifications](notifications) for more information.

