# Preview, then Activate


A worked agent session for the frequency filter: confirm the audience is
ready, preview exactly what a frequency range would export, then activate
exactly that range - with the server proving the two match. Every call below
is a plain MCP `tools/call`; the argument objects are shown as the agent sends
them and the results as excerpts of what comes back.

The numbers are from a real run. The only thing that changes between runs is
the ids.

**Before you start:** a connected agent ([Getting started](/mcp/getting-started))
and a `104` Completed audience that was built with a frequency analysis:
`analyses: {"frequency": true}` (POI), `{"apps_frequency": true}` (Apps) or
`{"web_frequency": true}` (WebDomain) on `create_audience`, or the matching
toggle in the Audience Manager. Audiences built without one carry no frequency
distribution and are refused by the preview - the filter is never
approximated, and no analysis can be added after the build.

## 1. Confirm the audience is ready

```json
get_audience  {"id": 88}
```

```json
{
  "id": 88,
  "name": "Kubota Test Audience US L30",
  "status": { "id": 104, "name": "Completed" },
  "is_activation_allowed": true,
  "results_count": 205188
}
```

`status.id` must be `104` and `is_activation_allowed` should be `true` - the
frequency filter does not change the eligibility gates, so an audience that is
blocked here stays blocked whatever range you pick.

## 2. Preview the range

Ask for the range you intend to export. The response is the exact device count
the Audience Manager shows as **Limit Audience** for the same Freq. Range:
the audience's stored frequency histogram (distinct visit days -> devices)
summed over the inclusive `[freq_min, freq_max]` range, which is the same
predicate the export applies. Nothing is created, queued, exported, scheduled
or billed, so preview as many ranges as the conversation needs.

```json
preview_activation  {"audience_id": 88, "freq_min": 2, "freq_max": 31}
```

```json
{
  "audience": { "id": 88, "status": { "id": 104, "name": "Completed" }, "is_activation_allowed": true },
  "dataset_type": "POI",
  "analysis_type": "frequency",
  "recency": [ { "dataset_type": "POI", "start_date": "07/01/2026", "end_date": "07/31/2026" } ],
  "source_count": 205188,
  "histogram_total": 208389,
  "filtered_count": 21656,
  "frequency_bounds": { "min": 1, "max": 31 },
  "histogram": [ { "index": 1, "counts": 186733 }, { "index": 2, "counts": 12904 }, "..." ],
  "applied_filters": { "freq_limit": true, "freq_min": 2, "freq_max": 31 },
  "filter_hash": "sha256:d6c9da3215a0f9d8902bab24c5e1b579f52cb11b6cbb76ca7ab8a032e0e1151b",
  "method": "histogram_sum",
  "as_of": "2026-08-20 23:18:11"
}
```

How to read it:

- `filtered_count` is exact - 21,656 devices were seen on 2 or more distinct
  days. This is the number to tell the user.
- An open-ended "N+" range is `freq_min: N` with `freq_max` set to
  `frequency_bounds.max`. "1+" therefore returns `histogram_total`.
- `source_count` is the audience total shown on the audience itself (an
  approximate distinct count) and `histogram_total` the exact histogram sum,
  so the two can differ slightly. Quote `filtered_count`, not a difference.
- `recency` is the audience's own date window, echoed read-only. It is not a
  preview input: to count against another window, build (or
  `estimate_audience_size`) a new audience.
- Keep `filter_hash` - it is the proof for step 3. Only `audience_id`,
  `freq_min` and `freq_max` are accepted; any other field is rejected rather
  than ignored.

## 3. Activate exactly that range

Discover the destination as usual - `lookup_reference` with dataset `common`
and catalogs `endpoint-connections`, then `pricing-models` and `datastreams`
for that connection's `partner_id` (see the
[Tools Reference](/mcp/tools-reference#activations)). Then send the same
`audience_id`, `freq_min` and `freq_max` you previewed, with `freq_limit: true`
and the `filter_hash` unchanged:

```json
create_activation  {
  "audience_id": 88,
  "endpoint_connection_id": 12,
  "pricing_model_id": 3,
  "datastreams": [ { "id": 7, "status": true } ],
  "description": "Kubota 2+ visit days",
  "freq_limit": true,
  "freq_min": 2,
  "freq_max": 31,
  "filter_hash": "sha256:d6c9da3215a0f9d8902bab24c5e1b579f52cb11b6cbb76ca7ab8a032e0e1151b",
  "idempotency_key": "kubota-2plus-2026-08-25"
}
```

```json
{
  "id": 501,
  "status": { "id": 100, "name": "Initiating" },
  "audience": { "id": 88, "name": "Kubota Test Audience US L30" },
  "filters": { "freq_limit": true, "freq_min": 2, "freq_max": 31 },
  "filter_hash": "sha256:d6c9da3215a0f9d8902bab24c5e1b579f52cb11b6cbb76ca7ab8a032e0e1151b"
}
```

The server recomputes the hash for the requested range on the audience as it
is stored now. A different range, or an audience that was rebuilt since the
preview, is rejected - the activation never applies anything other than what
was previewed. When that happens, run `preview_activation` again and use the
fresh hash.

## 4. Poll and read back

```json
get_activation  {"id": 501}
```

Poll until `data[0].status.id` is `104` (Completed) - `105` DataStreaming
comes first and means delivery is still in progress. The read echoes `filters`
and `filter_hash`, so any later reader can see which range the export applied.
Delivered data lands at the destination configured on the endpoint connection.
In this run the delivered file held exactly 21,656 device ids - the previewed
count.

## Rules for the agent

- Never send `freq_min` / `freq_max` without an explicit `freq_limit`; the
  request is rejected. `freq_limit: false` with bounds is an explicit "export
  the whole audience".
- A preview refusal ("not supported for this audience") means the audience has
  no usable frequency distribution - it was built without the Frequency
  analysis, is a lookalike or cohort, uses a day-part frequency, or carries
  more than one frequency analysis. Say so; do not estimate a count. If it
  was built without one, the fix is a new `create_audience` with the
  `analyses` key that matches its dataset.
- Recency is fixed by the audience definition. Do not try to pass dates.
- Preview is a read (120 requests/min per token); create is a write
  (30 requests/min). Pass an `idempotency_key` on the create so a retry can
  never activate twice.
