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

# Dimensions and labels

> Organize advertisers and campaigns with buyer-owned dimensions and labels.

## Overview

A **dimension** is a Buyer Account's named organizing axis, such as Market,
Quarter, or Brand. A **label** is one value from that dimension attached to an
advertiser or campaign. Dimensions make labels consistent across those objects:
the same value means the same thing everywhere in the account.

Every Buyer Account also has the built-in `tags` dimension. It is open, so you
can apply a new tag value without creating it first. There is no separate tag
object or tag tool.

Dimensions organize work; they do not grant authority, select inventory, change
targeting, or cross an AdCP boundary.

Dimensions do not have their own screen. They appear as object labels, search
filters, and buyer campaign-delivery report axes; setup happens in your flow
when you first organize work by an axis.

## Dimension fields

| Field        | Type                 | Notes                                                                                                                             |
| ------------ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | string               | Opaque server-issued identifier. Use it to read or update the dimension.                                                          |
| `key`        | string               | Immutable owner-chosen slug, unique in the Buyer Account. It is the key in `labels` and `filter.labels`.                          |
| `name`       | string               | Display name. Rename this without changing `key`.                                                                                 |
| `valuesMode` | `open` or `governed` | Open dimensions accept a new normalized value when you apply a label. Governed dimensions accept only their listed active values. |
| `values`     | array                | Each value has a stable `value`, display `name`, and `retired` state. Retired values stay in history but cannot be newly applied. |
| `appliesTo`  | array                | The object kinds this dimension may label: `advertiser`, `campaign`, or both.                                                     |
| `usage`      | object               | Read-only counts of labeled advertisers and campaigns.                                                                            |
| `retired`    | boolean              | Retired dimensions cannot receive new labels but remain readable.                                                                 |

## Create and manage dimensions

On the V3 MCP endpoint, use `save_dimension` to create a dimension with a
unique `key`, display `name`, value mode, applicable object kinds, and an
idempotency key. After creation, use its returned `id` for updates; `key` is
immutable. The same tool can add or rename values, merge a value into another
value, or retire a value or the whole dimension.

`mergeInto` must name an existing active target value. Merging moves existing
labels to that target but does not retire the source: retire a merged source
explicitly when it should no longer be available.

There can be at most 20 dimensions in a Buyer Account, 200 values in one
dimension, and 50 labels on one advertiser or campaign. The built-in `tags`
dimension counts toward the account's dimension limit and always remains open.

## Apply and find labels

Pass `labels` to `save_advertiser` or `save_campaign`:

```json theme={null}
{
  "labels": {
    "market": ["us", "canada"],
    "tags": ["launch"]
  }
}
```

Each supplied dimension replaces that dimension's labels on the object; pass
an empty array to clear that dimension. Omitting `labels` leaves labels
unchanged. `get` and `search` return the current labels as the same
`{ "dimensionKey": ["value"] }` shape.

Use `search` with `kind: "advertiser"` or `kind: "campaign"` and
`filter.labels`. The filter is AND across dimension keys and OR within a value
array. Use the literal `"unlabeled"` to find objects with no active value for
one dimension:

```json theme={null}
{
  "kind": "campaign",
  "filter": {
    "labels": { "market": ["us", "canada"], "quarter": "unlabeled" }
  }
}
```

List dimensions with `search({ "kind": "dimension" })`, optionally using
`filter.appliesTo`, then read one with `get({ "kind": "dimension", "id": "…" })`.
You cannot narrow `appliesTo` while the dimension still has labels on an object
kind being removed; clear or move those labels first.

## Group delivery by a label

For V3 buyer campaign delivery, pass a label axis as
`"labels.<dimensionKey>"` in `get_delivery.dimensions`:

```json theme={null}
{
  "report": "campaign_delivery",
  "dimensions": ["labels.market"],
  "range": { "startDate": "2026-08-01", "endDate": "2026-08-31" }
}
```

The report reads the current labels on both the campaign and its advertiser.
Rows with no active value are returned in the `"Unlabeled"` bucket. Because
labels are resolved when you query the report, a later relabeling reorganizes
historical rows too. An unknown, retired, or inapplicable key is rejected with
the account's available dimensions.

## Related

<CardGroup cols={2}>
  <Card title="Advertiser" href="/v2/object-guides/advertiser" icon="building">
    Advertiser ownership and fields
  </Card>

  <Card title="Campaign" href="/v2/object-guides/campaign" icon="bullhorn">
    Campaign ownership and fields
  </Card>
</CardGroup>
