Skip to content
Developers
Open app

Add tag options

POST
/v1/media-attributes/{id}/options
const url = 'https://api.focal.inc/v1/media-attributes/846196ad-9fa2-40a8-8938-655a962220e1/options';
const options = {
method: 'POST',
headers: {
'Idempotency-Key': 'looker-sync-2027-03-04-0001',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: '{"options":[{"name":"Evergreen","description":"Always-on assets that aren\'t tied to a single campaign."}]}'
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}

Append options to a tags field and return the updated definition (including the new options’ ids). Purely additive: existing options are never renamed, reordered, or removed, and a name that already exists is skipped rather than duplicated — so the call is safe to repeat.

Rejected with 400 on a non-tags field.

Required scope: media:write — unlike the other definition writes, adding an option can’t invalidate a stored value, so it rides on the same scope as writing values and needs no confirmation over MCP.

A field with allow_create: false (the setting that also stops the app from adding options while tagging) is closed to that scope, and needs spaces:write instead — the scope for the space’s own settings, with the same admin/owner requirement PATCH /v1/media-attributes/{id} applies when the credential acts for a specific user. A credential holding neither gets a 400. Defining options on a closed field this way is still purely additive: prefer it over PATCH, which replaces the option set.

Rate-limit cost: 10. Requires an Idempotency-Key.

id
required
string format: uuid

Example

846196ad-9fa2-40a8-8938-655a962220e1
Idempotency-Key
required
string
<= 255 characters

Example

looker-sync-2027-03-04-0001

Client-generated key (≤255 chars) for safe retries. A retry with the same key replays the original response instead of re-applying the write; reusing a key with a different body → 400, an in-flight key → 409.

Media typeapplication/json
object
options
required

Options to append, in order. Names that already exist on the field (case-insensitive) are skipped rather than duplicated, so the call is safe to repeat. At most 100 per request, and the field cannot exceed 499 options in total — a request that would go past that is rejected rather than partly applied.

Array<object>
object
name
required

The option’s label. Must be unique within the field (case-insensitive).

string
>= 1 characters <= 255 characters

Example

Spring Launch
description

Help text shown next to the option in Focal when picking tags. At most 500 characters; send an empty string to clear it.

string
<= 500 characters

Example

Assets for the Spring 2027 launch campaign.

Example

[
{
"name": "Evergreen",
"description": "Always-on assets that aren't tied to a single campaign."
}
]

OK

Media typeapplication/json
object
data
required
object
id
required

The attribute definition id — referenced by media payloads as attributes[].attribute_id.

string format: uuid
name
required

Display name of the field, as media payloads carry in attributes[].attribute_name.

string
type
required

The field’s kind — same enum as attributes[].attribute_type on media payloads. tags fields carry selectable options; fetch them via GET /v1/media-attributes/{id}. user fields hold user ids — resolve them via GET /v1/users.

string
Allowed values: text number tags checkbox date link user
multiple
required

Whether the field holds multiple values per media (e.g. multi-select). Mirrors attributes[].multiple.

boolean
space_id
required
string format: uuid
organization_id
required
string format: uuid
created_at
required
string format: date-time
updated_at
required
string format: date-time
options
required

For tags fields, the selectable options in display order. null for field types that have no options concept.

Array<object>
nullable
object
id
required

Stable option id — the value media payloads carry in attributes[].value for this option. Option renames keep this id; match on it rather than on name when tracking options over time.

string
name
required

Human-readable option label. This is the string media payloads carry in attributes[].display_value for this option.

string
description
required

The option’s help text, shown next to it in Focal when picking tags — what this option means, or when to use it. Empty string when unset; never null, so it’s safe to render directly. Not carried on media payloads, which reference the option by id/display_value only.

string
autofill
required

The field’s AI autofill configuration, or null when autofill is off — which is also what field types that can’t autofill (everything but text and tags) always report. For a tags field the model is additionally given each option’s name and description, so option descriptions act as per-option guidance on top of this instruction.

object
prompt
required

The instruction the AI follows, as plain text. A prompt written in the app with @mentions of other fields is flattened to @Label here.

string
allowed_media_types
required

The media kinds this runs on, or null for all of them.

Array<string>
nullable
Allowed values: statics videos
name_only
required

Whether the AI sees only the filename rather than analyzing the media itself.

boolean

Example

{
"data": {
"id": "846196ad-9fa2-40a8-8938-655a962220e1",
"name": "Campaign",
"type": "text",
"multiple": true,
"space_id": "6916bc3d-e1ab-425b-ac25-eefada01a9a2",
"organization_id": "b46d9033-24b2-4441-87ad-2151088fde01",
"created_at": "2027-03-04T10:15:00Z",
"updated_at": "2027-03-06T14:42:00Z",
"options": [
{
"id": "80f1e4d3-cbab-42a0-a397-318f348f5f93",
"name": "Spring Launch",
"description": "Assets for the Spring 2027 launch campaign."
}
],
"autofill": {
"prompt": "Pick the campaign this asset belongs to, based on its content and filename.",
"allowed_media_types": [
"videos"
],
"name_only": false
}
}
}

The request was malformed (invalid cursor, unknown type, validation failure, etc.). error.code is bad_request.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "bad_request",
"message": "Invalid request body",
"details": [
{
"field": "space_id",
"issue": "Invalid UUID"
}
]
}
}

Missing, invalid, or disabled token. error.code is unauthenticated.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "unauthenticated",
"message": "Bearer token is missing or invalid"
}
}

The token doesn’t have the scope this endpoint requires. error.code is forbidden.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "forbidden",
"message": "Token doesn't have the required scope"
}
}

Resource doesn’t exist or is outside the token’s space allow-list. The two cases share a response shape so a restricted token can’t probe for the existence of out-of-scope spaces. error.code is not_found.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "not_found",
"message": "Not found"
}
}

The request conflicts with the current state. Most commonly a concurrent request carrying the same Idempotency-Key is still in flight. error.code is conflict.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "conflict",
"message": "A request with this Idempotency-Key is already being processed"
}
}

Rate limit exceeded. error.code is rate_limited. Wait the number of seconds in the Retry-After header before retrying. Quotas are per-token; see the “Rate limiting” section at the top of this document.

Media typeapplication/json

Canonical error envelope. code is stable across releases and intended for programmatic handling; message is human-readable. details only appears for validation failures and lists the offending fields.

object
error
required
object
code
required
string
Allowed values: unauthenticated forbidden not_found bad_request conflict rate_limited internal_error
message
required
string
details
Array<object>
object
field
string
issue
required
string

Example

{
"error": {
"code": "rate_limited",
"message": "Rate limit of 1000 units per 60s exceeded (this request cost 5)"
}
}
Retry-After
integer
Example
12

Seconds to wait before retrying.