Audiences
Build, list, read and delete custom audiences. Audience creation is asynchronous: the create call returns immediately with a new id, and you poll the get endpoint until the audience reaches its completed lifecycle status. To run a completed audience on a recurring data window - rebuilt and optionally re-exported every cycle - see Schedules.
All audience endpoints are authenticated and JSON-only. Send Authorization: Bearer <token> and Accept: application/json on every call (plus Content-Type: application/json on the POST create). Reads use the read rate bucket (120
requests/min per caller); the create and delete use the write bucket (30
requests/min per caller).
Create Audience
POST /api/v2/analyses/audiences/create
Creates a custom audience for the authenticated user’s company from one or two
datasets. Two datasets are combined with an operator. An optional crossvisitation block narrows the
audience to people who visited selected points of interest; an optional
crosspurchase block runs the built audience against the affinity purchase
data. The audience is queued
asynchronously; poll
GET /api/v2/analyses/audiences/{id} for its
status and results_count.
Auth: bearer token + Accept: application/json + Content-Type: application/json. Rate limit: write bucket (30 requests/min). Optional:
Idempotency-Key header (see below).
The build counts toward your company’s monthly data-scan limit (see
Usage). When the limit has been reached and is enforced, the
call is refused with a 422 whose message names the limit and the date it
resets, before anything is created or queued.
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Audience name (max 255 chars). |
operator | string | Conditional | How to combine two datasets: AND, OR, or NOTIN. Required when datasets holds two blocks; rejected (422) when it holds one. Fetch the accepted values from GET /api/v2/analyses/reference/common/operators. |
project_id | integer | No | A project id owned by your company to file the audience under. |
datasets | object[] | Yes | One or two dataset blocks (array of size 1 or 2). |
crossvisitation | object | No | Optional POI crossvisitation analysis. Permission-gated - see below. |
crosspurchase | object | No | Optional cross purchase analysis run on the built audience. Permission-gated - see below. |
analyses | object | No | The frequency analyses to run as the audience builds - frequency (with its frequency_day_part sub-option), apps_frequency and web_frequency, all booleans - the same toggles as the Audience Manager and what the activation preview depends on. Permission-gated, each tied to its dataset type - see below. |
datastreams | object[] | No | Data stream visualizations to generate as the audience builds - see below. |
An audience holds one or two datasets. A single dataset takes no operator; two
datasets require an operator (AND, OR, or NOTIN). Each dataset is validated
and company-scoped identically. A second dataset that is present but missing its
type is rejected with 422.
Each datasets[i] block always carries a type, and (except for Cohorts and
Demographics) a start_date and end_date. The remaining fields depend on the type. The type
is one of the dataset types your company is entitled to, fetchable from
GET /api/v2/analyses/reference/common/dataset-types.
Common to each datasets[i]:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | The dataset type. Fetch the types your company is entitled to from GET /api/v2/analyses/reference/common/dataset-types - a type not enabled for your account is rejected with 422. |
start_date | string (Y-m-d) | Yes for all except Cohorts and Demographics | Window start date. |
end_date | string (Y-m-d) | Yes for all except Cohorts and Demographics | Window end date. |
signal_providers | string[] | Yes (all types except Cohorts and Demographics) | BID values identifying the signal source. Fetch valid values from GET /api/v2/analyses/reference/common/signal-providers. |
languages | string[] | No | Language codes. Fetch valid values from GET /api/v2/analyses/reference/common/languages. |
location | object | countries required (all types except Cohorts, AffinityTransactions and ProfileAttributes) | { countries[], states[], cities[], dmas[], zipcodes[] } (string arrays). countries come from GET .../reference/common/countries; states cascade via GET .../reference/common/states; cities cascade via GET .../reference/common/cities; dmas (POI and Origin only) come from GET .../reference/common/dmas. |
Every key in a dataset block must be one the block’s type defines (the common
keys above plus the type’s own fields below). Any other key - a misspelling, a
key from another type, or a filter the type does not have - is rejected with
422 naming the key, never silently ignored. The same applies inside
location.
WebDomain fields:
start_date must fall within the last 45 days of available data: web data
lands with a ~48-hour delay, so the window ends two days ago (UTC). Older
visitation data is archived and unreadable - an earlier start_date is
rejected with 422. The window rolls forward one day at UTC midnight.
| Field | Type | Required | Description |
|---|---|---|---|
iab_category_codes | integer[] | One of iab_category_codes / web_domains | IAB category ids. Fetch valid values from GET .../reference/web/iab-categories (and .../web/iab-subcategories). |
web_domains | string[] | One of iab_category_codes / web_domains | Web domains to target. Domains must exist in the catalog - fetch valid values from GET .../reference/web/domains; a domain outside the catalog is rejected with 422. |
web_ref_domains | string[] | No | Referrer domains to target. Fetch valid values from GET .../reference/web/ref-domains. |
device_types | string[] | No | Web device type names. Fetch valid values from GET .../reference/web/device-types. |
device_makes | string[] | No | Web device make names. Fetch valid values from GET .../reference/web/device-makes. |
device_oses | string[] | No | Web device OS names. Fetch valid values from GET .../reference/web/device-oses. |
browsers | string[] | No | Web browser names. Fetch valid values from GET .../reference/web/browsers. |
max_devices_per_ip | integer | No | Match strictness: how many devices may share one household/IP. 1 (very strict) to 5 (more reach). Defaults to 3 (recommended). |
CTV fields:
| Field | Type | Required | Description |
|---|---|---|---|
ctv_vendor_names | string[] | No | CTV vendor names. Fetch valid values from GET .../reference/ctv/vendors. |
ctv_content_type_names | string[] | No | CTV content type names. Fetch valid values from GET .../reference/ctv/content-types. |
ctv_content_genre_names | string[] | No | CTV content genre names. Fetch valid values from GET .../reference/ctv/content-genres. |
ctv_channel_names | string[] | No | CTV channel names. Fetch valid values from GET .../reference/ctv/channel-names. |
iab_codes | array | No | IAB codes. Fetch valid values from GET .../reference/web/iab-categories. |
ctv_device_types | string[] | No | CTV device type names. Fetch valid values from GET .../reference/ctv/device-types. |
ctv_device_makes | string[] | No | CTV device make names. Fetch valid values from GET .../reference/ctv/device-makes. |
ctv_device_oses | string[] | No | CTV device OS names. Fetch valid values from GET .../reference/ctv/device-oses. |
ctv_connection_types | string[] | No | CTV connection type names. Fetch valid values from GET .../reference/ctv/connection-types. |
ctv_isps | string[] | No | CTV ISP names. Fetch valid values from GET .../reference/ctv/isps. |
ctv_series | string[] | No | CTV series names. Fetch valid values from GET .../reference/ctv/series. |
Cohorts fields:
| Field | Type | Required | Description |
|---|---|---|---|
cohort_id | integer | Yes | A completed cohort id owned by your company. Fetch valid ids from GET .../reference/cohorts/get-cohorts, or create one from your own cloud file via Create Cohort. (No dates or location.) |
Apps fields:
| Field | Type | Required | Description |
|---|---|---|---|
app_ids | integer[] | At least one of categories / taxonomies / bundle_ids / app_ids | App ids to target. Fetch valid values from GET .../reference/apps/bundle-ids. |
bundle_ids | string[] | At least one of categories / taxonomies / bundle_ids / app_ids | App bundle ids to target. Fetch valid values from GET .../reference/apps/bundle-ids. |
categories | array | At least one of categories / taxonomies / bundle_ids / app_ids | App category ids. Fetch valid values from GET .../reference/apps/categories. |
taxonomies | array | At least one of categories / taxonomies / bundle_ids / app_ids | App taxonomy ids. Fetch valid values from GET .../reference/apps/taxonomies. |
device_os | string[] | No | App device OS values. Fetch valid values from GET .../reference/apps/os. |
refine | object | No | Post-build refinement: keep only the most active devices. Permission-gated, single-dataset audiences only - see Refine. |
Apps location supports countries only: sending location.states,
location.cities, location.dmas, or location.zipcodes on an Apps dataset
is rejected with 422.
POI fields:
Targets people by the points of interest they physically visited. The POI catalogs
cascade: segments -> categories (?segments[]) -> brands (?categories[]) ->
locations (?brands[]). Unknown POI category, brand and location ids are rejected
with 422.
| Field | Type | Required | Description |
|---|---|---|---|
categories | integer[] | At least one of categories / analysisdata / locations | POI category ids, as a FLAT list of integers ([12, 13]). An object here, such as [{"id": 12, "brands": [3]}], is rejected with 422. Fetch valid values from GET .../reference/poi/categories (cascades from .../poi/segments). |
analysisdata | integer[] | At least one of categories / analysisdata / locations | POI brand ids. This is the brand field: there is no brands key on a POI block, and brands are never nested inside categories. Fetch valid values from GET .../reference/poi/brands. |
locations | array | At least one of categories / analysisdata / locations | POI location identifiers, interpreted per location_identifier_type. Fetch candidates from GET .../reference/poi/locations. |
location_identifier_type | string | No | How locations are interpreted: none, location_id, external_id, store_id, placekey, h3_index, or h3_index_integer. |
location.countries | string[] | Yes | Country codes (at least one). From GET .../reference/common/countries. |
location.states | string[] | No | State codes. Cascade via GET .../reference/common/states. |
location.cities | string[] | No | City names. Cascade via GET .../reference/common/cities. |
location.dmas | string[] | No | DMA market labels. From GET .../reference/common/dmas. |
location.zipcodes | string[] | No | ZIP codes. Cascade from cities via GET .../reference/common/zipcodes (paginated). |
signal_providers | string[] | Yes | BID values identifying the signal source (at least one). From GET .../reference/common/signal-providers. |
time_limits | object | No | { process: boolean, start: 0-23, end: 0-23 }. Hour-of-day window applied only when process is true. |
day_limits | object | No | { process: boolean, days: integer[] }. Day-of-week filter applied only when process is true; days use ISO numbering (1 = Monday .. 7 = Sunday). |
distance_limits | object | No | { process: boolean, distance: number, unit: "miles" | "kilometers" }. Radius applied only when process is true. |
refine | object | No | Post-build refinement: keep only the most active devices. Permission-gated, single-dataset audiences only - see Refine. |
The console’s audience-level quality filters (anomalous devices, GPS-only signals, anomalous POIs, GPS decimals) are not exposed on this API and default to off.
AffinityTransactions fields:
Targets people by what they actually bought. The purchase catalogs cascade:
categories -> sub-categories (?categories[]) -> brands (?categories[],
?subcategories[]). Unknown category, sub-category, brand and demographic
values are rejected with 422.
Affinity purchase data is United States only. location.countries is optional
here and is always stored as ["USA"]; sending any other country code is
rejected with 422, as is location.dmas (the type reads states, cities and
postal codes only).
Affinity purchase data lands one week at a time, and a completed week is only
fully loaded about eleven days after it ends. end_date therefore cannot run
past the most recent fully-settled week - the latest Sunday that is at least 11
days before today (UTC) - and a later date is rejected with 422. This boundary
advances by one week automatically each Thursday, so the newest selectable end
date moves forward on its own; there is no fixed cut-off to track.
| Field | Type | Required | Description |
|---|---|---|---|
categories | integer[] | At least one of categories / brands | Affinity purchase category ids. Fetch valid values from GET .../reference/affinity-transactions/categories. |
brands | string[] | At least one of categories / brands | Affinity brand id strings. Fetch valid values from GET .../reference/affinity-transactions/brands. |
subcategories | string[] | No | Sub-category strings (merchant category descriptions) cascading from categories. Fetch valid values from GET .../reference/affinity-transactions/subcategories. Picked without any brands, they are resolved to the brands they cover. |
incomes | string[] | No | Income bands. Fetch valid values from GET .../reference/affinity-transactions/incomes. |
ages | string[] | No | Age bands. Fetch valid values from GET .../reference/affinity-transactions/ages. |
genders | string[] | No | Gender values. Fetch valid values from GET .../reference/affinity-transactions/genders. |
ethnicities | string[] | No | Ethnicity values. Fetch valid values from GET .../reference/affinity-transactions/ethnicities. |
channels | string[] | No | Purchase channel: B&M (in-store) and/or ONLINE. |
spend_min | number | No | Minimum total spend (USD) across the date window. |
spend_max | number | No | Maximum total spend (USD) across the date window. |
txn_min | number | No | Minimum number of transactions across the date window. |
txn_max | number | No | Maximum number of transactions across the date window. |
analysis_spend_frequency | boolean | No | Also compute the spend distribution for the built audience. Defaults to false. |
analysis_transactions_frequency | boolean | No | Also compute the transaction-count distribution for the built audience. Defaults to false. |
max_devices_per_ip | integer | No | Match strictness: how many devices each shopper may expand to. 1 (very strict) to 5 (more reach). Defaults to 3 (recommended). |
An AffinityTransactions dataset block:
{
"type": "AffinityTransactions",
"start_date": "2025-01-01",
"end_date": "2025-03-31",
"signal_providers": ["BID001"],
"categories": [1],
"subcategories": ["Eating Places, Restaurants"],
"brands": ["501"],
"incomes": ["100k-150k"],
"channels": ["B&M"],
"spend_min": 50,
"txn_min": 2,
"max_devices_per_ip": 3,
"location": { "states": ["CA"] }
}Demographics fields:
Targets people by their household demographic attributes. The four dictionaries
are flat - no cascade - and at least one of them must carry a selection.
Unknown values are rejected with 422.
This type carries no date window and no signal providers: sending
start_date, end_date or signal_providers on a Demographics dataset is
rejected with 422. Its location supports countries only, so
location.states, location.cities, location.zipcodes and location.dmas
are rejected too.
| Field | Type | Required | Description |
|---|---|---|---|
genders | string[] | At least one of genders / ages / marital_statuses / incomes | Gender values. Fetch valid values from GET .../reference/demographics/genders. |
ages | string[] | At least one of genders / ages / marital_statuses / incomes | Age ranges. Fetch valid values from GET .../reference/demographics/ages. |
marital_statuses | string[] | At least one of genders / ages / marital_statuses / incomes | Marital status values. Fetch valid values from GET .../reference/demographics/marital-statuses. |
incomes | string[] | At least one of genders / ages / marital_statuses / incomes | Income ranges. Fetch valid values from GET .../reference/demographics/incomes. |
location.countries | string[] | Yes | Country codes (at least one). From GET .../reference/common/countries. |
A Demographics dataset block:
{
"type": "Demographics",
"genders": ["F"],
"ages": ["25-34", "35-44"],
"incomes": ["100k-150k"],
"location": { "countries": ["USA"] }
}Deidentified fields:
Delivers the deidentified signals themselves for a country and date window,
rather than a targeted device list - so instead of filters it takes fields:
which signal fields the delivery carries.
fields selects output columns only. It does not filter rows: there is no
device, OS or platform filter on this type (fields.userDetails: ["deviceos"]
adds the OS column to the delivery, it does not restrict the delivery to an
OS). A filter-shaped key such as deviceos is rejected with 422.
fields is an object keyed by group (geoLocation, advertising,
userDetails, ipDetails, privacy, general). Every group is optional -
send only the groups you want, or omit fields entirely for the default shape.
Fetch the fields and the group each belongs to from
GET .../reference/deidentified/fields;
an unknown field, or a field sent under a group it does not belong to, is
rejected with 422.
This type is delivered on its own: an audience whose dataset is Deidentified
takes exactly one dataset block, so pairing it with a second one (and therefore
an operator) is rejected with 422.
Its location supports countries only, so location.states, location.cities,
location.zipcodes and location.dmas are rejected. When
location.countries includes USA, the date window may cover at most two weeks
per delivery; a longer window is rejected with 422.
| Field | Type | Required | Description |
|---|---|---|---|
fields | object | No | Which signal fields the delivery carries, keyed by group. Fetch the fields and their groups from GET .../reference/deidentified/fields. |
signal_providers | string[] | Yes | BID values identifying the signal source (at least one). From GET .../reference/common/signal-providers. |
start_date | string (Y-m-d) | Yes | Window start. |
end_date | string (Y-m-d) | Yes | Window end. At most two weeks after start_date when location.countries includes USA. |
location.countries | string[] | Yes | Country codes (at least one). From GET .../reference/common/countries. |
A Deidentified dataset block:
{
"type": "Deidentified",
"start_date": "2026-01-05",
"end_date": "2026-01-18",
"signal_providers": ["BID001"],
"fields": {
"geoLocation": ["latitude", "longitude"],
"ipDetails": ["ipisp"],
"general": ["d_utc"]
},
"location": { "countries": ["USA"] }
}ProfileAttributes fields:
Targets people by the profile attributes they carry. profile_attributes is a
list of attribute rows, each one a category, a key under that category, and the
values of that key to match. Rows are combined with AND - a device must
match every row.
The attribute catalogs cascade: categories -> keys (?category_ids[]) ->
values (?category_ids[], ?key). Each row is checked at all three levels: an
unknown category, a key that does not belong to the row’s category, or a value
that does not belong to the row’s category and key is rejected with 422
naming the exact row.
location is not applied to this dataset type. Profile attribute data
carries no geography, so the builder discards the whole location block.
location.countries is therefore optional - it is still accepted, for
backward compatibility with integrations written when it was required, but it
never filters anything. location.states, location.cities,
location.zipcodes and location.dmas are rejected outright.
Profile attribute data is delivered quarterly. start_date and end_date must
fall inside the delivered window published by
GET .../reference/profile-attributes/recency-limits;
a date outside it is rejected with 422. The stored window is expanded out to
whole quarters - start_date to the first day of its quarter and end_date to
the last day of its quarter.
| Field | Type | Required | Description |
|---|---|---|---|
profile_attributes | object[] | Yes | Attribute rows (at least one), combined with AND. |
profile_attributes[].category_id | integer | Yes | An attribute category id. Fetch valid values from GET .../reference/profile-attributes/categories. |
profile_attributes[].key | string | Yes | An attribute key under that category. Fetch valid values from GET .../reference/profile-attributes/keys with ?category_ids[]. |
profile_attributes[].value_ids | integer[] | Yes | Value ids of that key (at least one). Fetch valid values from GET .../reference/profile-attributes/values with ?category_ids[] and ?key. |
signal_providers | string[] | Yes | BID values identifying the signal source (at least one). From GET .../reference/common/signal-providers. |
start_date | string (Y-m-d) | Yes | Window start, inside the delivered window. |
end_date | string (Y-m-d) | Yes | Window end, inside the delivered window. |
location.countries | string[] | No | Accepted but never applied - this dataset has no geography. Safe to omit. |
A ProfileAttributes dataset block (no location needed):
{
"type": "ProfileAttributes",
"start_date": "2026-04-01",
"end_date": "2026-06-30",
"signal_providers": ["BID001"],
"profile_attributes": [
{ "category_id": 1, "key": "auto_intent", "value_ids": [10, 12] },
{ "category_id": 2, "key": "credit_band", "value_ids": [30] }
]
}Origin fields:
Targets people by their home location - where a device originates - rather than by the places it visited. Each device’s home is resolved once per week and placed by point-in-polygon against the ZIP code and DMA boundaries, so every filter below narrows that resolved home location.
Its only filters are geographic: beyond the common signal_providers, dates
and location, it defines no key of its own.
Its data is weekly - a device’s home is resolved once per week, and there is no day in the data - so a sub-week window cannot exist. Any dates are accepted, and the window is widened to the whole Monday-to-Sunday weeks it touches: Tuesday to Friday builds, and is stored as, that full week.
Origin data exists for a limited set of countries. Fetch the covered set from
GET .../reference/common/countries?datasetType=Origin;
a country outside it is rejected with 422.
| Field | Type | Required | Description |
|---|---|---|---|
signal_providers | string[] | Yes | BID values identifying the signal source (at least one). From GET .../reference/common/signal-providers?dataType=Origin. |
start_date | string (Y-m-d) | Yes | Window start. Widened back to the Monday of its week. |
end_date | string (Y-m-d) | Yes | Window end, on or after start_date. Widened forward to the Sunday of its week. |
location.countries | string[] | Yes | Country codes (at least one) with Origin coverage. From GET .../reference/common/countries?datasetType=Origin. |
location.states | string[] | No | State codes. From GET .../reference/common/states. |
location.cities | string[] | No | City names. From GET .../reference/common/cities. |
location.dmas | string[] | No | DMA labels exactly as returned by GET .../reference/common/dmas - the label string, never a numeric code. |
location.zipcodes | string[] | No | ZIP codes. From GET .../reference/common/zipcodes. |
An Origin dataset block:
{
"type": "Origin",
"start_date": "2026-08-31",
"end_date": "2026-09-13",
"signal_providers": ["BID001"],
"location": {
"countries": ["USA"],
"states": ["CA"],
"dmas": ["803 - Los Angeles, CA"]
}
}Refine
The optional per-dataset refine object refines the audience after it is
built: devices are ranked by a behavioral metric and only a subset is kept -
the top X% (percentile), everyone at or above a minimum event count
(threshold), or the top N devices (rank). The refined audience keeps its
full data shape; results_count and every downstream activation reflect the
refined device set.
Refine is available on POI and Apps datasets, and only for
single-dataset audiences - a refine block on any other dataset type, or
on either dataset of a two-dataset audience, is rejected with 422.
Refine is a gated feature. It requires additional permissions that your
Account Manager can enable for your account. If a refine block is present and
the feature is not enabled, the request is rejected with 403 (never silently
ignored). Omitting the block entirely requires nothing.
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | How the subset is selected: percentile (keep the top X% by the metric), threshold (keep devices with at least value events), or rank (keep the top value devices). |
metric | string | Yes | The behavioral metric to rank devices by. POI: visit_count or visit_days. Apps: app_usage_count or app_usage_days. |
value | number | Yes | Meaning depends on type: the percentage to keep for percentile (greater than 0 and less than 100), the minimum event count for threshold, or the number of devices for rank (whole number, at least 1). |
fraud_cutoff_percentile | integer | No | Drop outlier devices above this activity percentile (1-100, e.g. 99) before the cut, so bot-like devices do not crowd out the subset you keep. |
max_value | integer | No | Upper bound on the metric, threshold type only - keeps devices between value and max_value events. Rejected with 422 on the other types. |
A refined POI dataset block:
{
"type": "POI",
"start_date": "2025-01-01",
"end_date": "2025-03-31",
"signal_providers": ["BID001"],
"categories": [101],
"location": { "countries": ["USA"] },
"refine": {
"type": "percentile",
"metric": "visit_count",
"value": 10,
"fraud_cutoff_percentile": 99
}
}Crossvisitation
The optional top-level crossvisitation object narrows the audience to people who
physically visited selected points of interest (POIs) within a date window and
optional time-of-day and distance limits. It sits alongside datasets in the
body and is available only when the request contains a POI dataset - a
crossvisitation block on any other dataset type is rejected. When the block is
present it carries the same requirements as a POI dataset: a date window
(start_date / end_date), at least one country, and exactly one category.
Crossvisitation is a gated feature. It requires additional permissions that
your Account Manager can enable for your account. If a crossvisitation block is
present and the feature is not enabled, the request is rejected with 403 (never
silently ignored). Omitting the block entirely requires nothing.
POI id sources. Pick the POI values from the read-only
Dataset Types - POI catalogs:
categories from GET .../reference/poi/categories,
brands from GET .../reference/poi/brands,
and locations from GET .../reference/poi/locations.
(Creating and managing the underlying POI data itself is the separate
My POI Data surface.)
| Field | Type | Required | Description |
|---|---|---|---|
start_date | string (Y-m-d) | Yes | Start of the visitation window. |
end_date | string (Y-m-d) | Yes | End of the visitation window. |
poi_level | boolean | No | Resolve at the individual-POI level rather than the parent brand/category. |
filters | string[] | No | Quality filters: any of anomalous_devices, gps_only, anomalous_pois. |
categories | integer[] | Yes (exactly one) | A single POI category id (see above). The block requires exactly one category. |
brands | integer[] | No | POI brand ids (see above). |
locations | array | No | POI location identifiers, interpreted per location_identifier_type. |
location_identifier_type | string | No | How locations are interpreted: none, location_id, external_id, store_id, placekey, h3_index, or h3_index_integer. |
location | object | countries required | Geographic scope { countries[], states[], cities[], dmas[], zipcodes[] } - countries needs at least one entry, the rest are optional. countries come from GET .../reference/common/countries. |
time_limits | object | No | { process: boolean, start: 0-23, end: 0-23 }. Hour-of-day window applied only when process is true. |
day_limits | object | No | { process: boolean, days: integer[] }. Day-of-week filter applied only when process is true; days use ISO numbering (1 = Monday .. 7 = Sunday). |
distance_limits | object | No | { process: boolean, distance: number, unit: "miles" | "kilometers" }. Radius applied only when process is true. |
Frequency analyses
The optional top-level analyses object runs the frequency analyses as the
audience builds - the same toggles the Audience Manager offers. Each one
stores, for every device in the audience, the number of distinct days it was
seen on its dataset:
| Field | Type | Required | Description |
|---|---|---|---|
frequency | boolean | No | true runs the Visitation Frequency analysis: distinct days a device was seen at the POI dataset’s points of interest. Requires a POI dataset. |
frequency_day_part | boolean | No | The Visitation Frequency by Day part sub-option: true buckets the Visitation Frequency by hour of the day instead of by visit day. Requires frequency: true, and is not available when the request holds an Apps dataset. A day-part audience cannot be previewed (hours are not visit counts); its activation applies the Day Part filter instead. |
apps_frequency | boolean | No | true runs the Apps Frequency analysis: distinct days a device used the Apps dataset’s apps. Requires an Apps dataset. |
web_frequency | boolean | No | true runs the Web Frequency analysis: distinct days a device visited the WebDomain dataset’s domains. Requires a WebDomain dataset; the activation preview supports it on single-dataset WebDomain audiences. |
Send the flavour that matches your dataset when you may later want to activate
only the devices seen on a minimum number of days (“2+ visits”). The analysis
stores the distinct-day histogram that
Preview Activation
sums and that the freq_min / freq_max filter of
Create Activation
applies. An audience built without a frequency analysis cannot be previewed or
filtered by frequency, and none can be added after the build. A two-dataset
audience may carry more than one flavour, exactly as in the Audience Manager,
but the preview only resolves an audience that carries exactly one.
The frequency analyses are a gated feature. They require additional
permissions that your Account Manager can enable for your account. If any of
them is true and the feature is not enabled, the request is rejected with
403 (never silently ignored). Omitting the object, or sending false,
requires nothing.
Each flavour needs its dataset. frequency needs a POI block,
apps_frequency an Apps block and web_frequency a WebDomain block: a
flavour sent without its dataset is rejected with 422 naming it, and so is
frequency_day_part without frequency or next to an Apps block. Any other
key under analyses is rejected with 422 naming it.
{
"name": "Coffee shop visitors - January",
"datasets": [
{
"type": "POI",
"start_date": "2026-01-01",
"end_date": "2026-01-31",
"signal_providers": ["BID001"],
"categories": [101],
"location": { "countries": ["USA"] }
}
],
"analyses": { "frequency": true }
}Data Stream Visualizations
An audience can generate a set of charts while it builds - visitation patterns, dwell time, demographics, CTV and web breakdowns and so on - which are then viewed in the Intuizi console on the audience’s Data Streams tab.
Opt in with the optional top-level datastreams array. It takes the same shape
as the one on activations, so a client that already
speaks one speaks both:
| Field | Type | Required | Description |
|---|---|---|---|
datastreams[].id | integer | Yes | The data stream id, from the reference catalog below. |
datastreams[].visualizing_status | boolean | No | true to generate this stream’s visualizations. Omitted or false means the stream is listed but not generated. |
{
"name": "Airport visitors - September",
"datasets": [ { "type": "POI", "start_date": "2026-09-01", "end_date": "2026-09-10" } ],
"datastreams": [
{ "id": 21, "visualizing_status": true },
{ "id": 14, "visualizing_status": true }
]
}The rendered charts are not returned by this API. There is no endpoint that
serves a visualization payload and no PDF export. datastreams controls what
gets built, and the results are read in the console. While the charts are drawn,
the audience reads 109 Visualizing data streams, before 105 and 104
Completed, so keep polling through it (see
Status Codes).
Where the ids come from. List what you may use, scoped to the dataset you are about to build:
GET /api/v2/analyses/reference/common/datastream-visualizations?dataset_type=POIThe list is scoped to the caller: every public stream, plus the private ones
assigned to your company. Streams without an active visualization are never
listed. Each item carries id, slug, name, dataset_types and
visual_count.
Mismatches are rejected, not dropped. A stream that does not apply to this
audience’s dataset types is a 422 naming the stream and the types it does
support - it is not silently ignored, because a stream built against the wrong
dataset produces a broken chart rather than an empty one. An id you are not
permitted to use is reported the same way as one that does not exist.
Cross Purchase
The optional top-level crosspurchase object runs the built audience
against the affinity purchase data: the audience’s devices are matched into
purchase transactions within your date window, scoped to the target categories,
sub-categories and brands you select. It sits alongside datasets in the body.
Because it runs on the finished audience, it is available with any dataset
combination - one or two datasets, any type. The analysis results are surfaced
in the Audience Manager alongside the audience.
Cross purchase is a gated feature. It requires additional permissions that
your Account Manager can enable for your account. If a crosspurchase block is
present and the feature is not enabled, the request is rejected with 403
(never silently ignored). Omitting the block entirely requires nothing.
Target value sources. Pick the target values from the read-only
Transactions catalogs:
target_categories from GET .../reference/affinity-transactions/categories,
target_subcategories from GET .../reference/affinity-transactions/subcategories,
and target_brands from GET .../reference/affinity-transactions/brands.
| Field | Type | Required | Description |
|---|---|---|---|
start_date | string (Y-m-d) | Yes | Start of the purchase window. |
end_date | string (Y-m-d) | Yes | End of the purchase window. The range may cover at most 2 calendar months, and cannot run past the most recent fully-settled purchase week - the latest Sunday at least 11 days before today (UTC), which advances each Thursday. A later date is rejected with 422. |
target_categories | integer[] | At least one of target_categories / target_subcategories / target_brands | Affinity category ids to scope the analysis to. |
target_subcategories | string[] | At least one of target_categories / target_subcategories / target_brands | Affinity sub-category strings (verbatim values from the reference read). |
target_brands | string[] | At least one of target_categories / target_subcategories / target_brands | Affinity brand id strings. |
A crosspurchase block on a request body:
{
"name": "Coffee visitors vs dining purchases",
"datasets": [ { "type": "POI", "...": "..." } ],
"crosspurchase": {
"start_date": "2025-01-01",
"end_date": "2025-02-28",
"target_categories": [1],
"target_brands": ["501"]
}
}WebDomain,
CTV, POI and Origin read the full location block (POI and Origin
also take location.dmas); Apps, Demographics,
Deidentified and ProfileAttributes read
location.countries only;
AffinityTransactions is United States only and reads location.states,
location.cities and location.zipcodes; Cohorts takes neither dates nor
location, and Demographics takes no dates.WebDomain windows roll: start_date must fall within the last 45 days of
available data at the moment you send the request - substitute a current
window for the dates below.
curl -X POST "https://console.intuizi.com/api/v2/analyses/audiences/create" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: <UNIQUE_KEY>" \
-d '{
"name": "US auto-intenders on tech sites",
"datasets": [
{
"type": "WebDomain",
"start_date": "2026-07-01",
"end_date": "2026-07-28",
"signal_providers": ["BID001"],
"iab_category_codes": [1, 4],
"web_domains": ["example.com"],
"device_types": ["Mobile"],
"browsers": ["Chrome"],
"languages": ["en"],
"location": { "countries": ["USA"] }
}
]
}'Response
The create response is the freshly queued audience (status Initiating,
results_count 0).
{
"status": "success",
"code": 201,
"message": "Resource created successfully.",
"data": [
{
"id": 88,
"name": "US auto-intenders on tech sites",
"status": { "id": 100, "name": "Initiating" },
"is_cohort": false,
"is_lookalike": false,
"results_count": 0,
"created_at": "2025-01-01 12:00:00"
}
]
}Idempotency
The optional Idempotency-Key header makes a create safe to retry. The key is
caller-generated: any unique string up to 255 characters (a UUID v4 is
typical), one per logical create - reuse it only when retrying that same
request. The first
request with a given key runs normally and the successful (2xx) response is cached
per caller. A retry with the same key and the same body replays the stored
response verbatim with an Idempotency-Replayed: true header, so no duplicate
audience is created. A retry with the same key but a different body returns
409 Conflict. See Idempotency for the full replay
semantics and the eight endpoints that honor the header.
List Audiences
GET /api/v2/analyses/audiences/index
Lists the audiences owned by the authenticated user’s company, most recent first, paginated.
Auth: bearer token + Accept: application/json. Rate limit: read bucket (120
requests/min).
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
per_page | integer | No | Items per page. Defaults to 25, capped at 100. |
page | integer | No | Page number (standard pagination). |
search | string | No | Optional free-text filter on the audience name (case-insensitive contains). |
curl "https://console.intuizi.com/api/v2/analyses/audiences/index?per_page=25" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"Response
{
"status": "success",
"code": 200,
"message": "Resources fetched successfully.",
"data": {
"items": [
{
"id": 88,
"name": "Coffee Buyers NYC",
"status": { "id": 104, "name": "Completed" },
"is_cohort": false,
"is_lookalike": false,
"results_count": 482311,
"is_activation_allowed": true,
"eligibility": {
"allowed": true,
"reasons": [],
"metrics": {"unique_eids": 482311, "unique_scids": null, "eid_scid_ratio": null, "is_affinity": false}
},
"totals": {"uniques": 482311, "visits": 1203440, "avg_uniques": 16077, "avg_visits": 40114},
"source_audience": null,
"created_by": { "name": "Jane Doe", "email": "jane.doe@acme.example" },
"project": { "id": 4, "name": "Retail 2025" },
"operator": "AND",
"dataset": [
{ "analysis_type": "WebDomain", "start_date": "01/01/2025", "end_date": "03/31/2025" },
{ "analysis_type": "Apps", "start_date": "01/01/2025", "end_date": "03/31/2025" }
],
"created_at": "2025-01-01 12:00:00",
"updated_at": "2025-01-10 09:30:00"
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
}Get Audience
GET /api/v2/analyses/audiences/{id}
Retrieves a single audience by id.
The same audience is also readable at GET /api/v2/my-data/audiences/{id} for
backward compatibility. The two responses differ by two fields: this
/analyses/audiences/{id} read includes the operator field (the
two-dataset combination mode) and totals (the flat metric whitelist), while
the /my-data/audiences/{id} read has neither - it returns eligibility but
not totals.
Auth: bearer token + Accept: application/json. Rate limit: read bucket (120
requests/min).
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The audience id to fetch. |
curl "https://console.intuizi.com/api/v2/analyses/audiences/88" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"Response
created_by is always an object (empty {} when no creator resolves), never
null. is_lookalike is true when this audience is the result of a
Lookalike Model run - false
for every ordinarily-built audience. is_activation_allowed is the verdict of the activation eligibility engine - the same
gates the console UI, the activation endpoints and the scheduler apply:
Gate (reasons[].code) | Rule |
|---|---|
minimum_devices | at least 500 unique devices (1,000 for lookalike outputs) |
affinity_device_coverage | audiences containing AffinityTransactions data: unique EIDs must exceed 2x unique SCIDs |
scid_count_unavailable | Affinity audience built before SCID totals were stored - duplicate and rebuild it |
audience_expired | a notice, not a block: standard audiences whose latest dataset end date is older than 90 days cannot be delivered as MAIDs or IPs (mapping keys are retained for 90 days). blocks_identifiers = ["MAID", "IP"]; activation with an EID / SCID / HEM pricing model is allowed, a MAID or IP pricing model is rejected with 422. Affinity, lookalikes and cohorts are exempt |
When blocked, eligibility.reasons[] carries the code, a human message, the
threshold used and the observed aggregate counts (for Affinity: unique_eids,
unique_scids, eid_scid_ratio, required_unique_eids). eligibility.notices[]
has the same shape plus blocks_identifiers: rules that only apply to some
output identifiers. They leave allowed true; the activation create rejects a
pricing model whose identifiers fall in blocks_identifiers. eligibility.metrics
always returns unique_eids, unique_scids (null when the audience has no
Affinity data), eid_scid_ratio and is_affinity. totals is the same metric
whitelist the console shows (keys vary by dataset type, e.g. uniques, scids,
transactions, amount, visits, signals, unique_eips). Only aggregates are
returned - never raw SCIDs or device identifiers.
dataset is a trimmed summary with one entry per dataset block (one or
two entries). A Cohorts entry also carries cohort, the cohort it reads.
operator carries the combination mode for a two-dataset audience
(AND, OR, or NOTIN), and is null for a single-dataset audience.
Two fields say what an audience was built from, so you can follow it by id instead of by name:
source_audience- the seed audience a Lookalike Model was built from (thesource_audience_idit was created with).nullfor every other audience.dataset[].cohort- on aCohortsentry, the cohort it reads. Get Cohort then says how that cohort was created (source) and, for one built from an audience, which audience (source_audience).
Each is { "id", "name" }, or null when the audience or cohort it points to
has been deleted or does not belong to your company - so an id you get here is
always one you can fetch.
"source_audience": null,
"operator": "AND",
"dataset": [
{ "analysis_type": "Cohorts", "start_date": "", "end_date": "", "cohort": { "id": 42, "name": "Loyalty program members" } },
{ "analysis_type": "CTV", "start_date": "01/27/2026", "end_date": "07/27/2026" }
]The read returns the datasets and operator only. A crossvisitation block or an
analyses object sent on create is not echoed back here - they live outside
the public dataset shape and do not round-trip on read.
recipe_hash and normalized_payload are the canonical recipe stamped at
create time: the same hash a prior
Estimate Audience Size call returned
for the identical payload, and the normalized body it was computed from. Both
are null for audiences created in the console UI or before this field
existed.
{
"status": "success",
"code": 200,
"message": "Resource fetched successfully.",
"data": [
{
"id": 88,
"name": "Coffee Buyers NYC",
"status": { "id": 104, "name": "Completed" },
"is_cohort": false,
"is_lookalike": false,
"results_count": 482311,
"is_activation_allowed": true,
"eligibility": {
"allowed": true,
"reasons": [],
"metrics": {"unique_eids": 482311, "unique_scids": null, "eid_scid_ratio": null, "is_affinity": false}
},
"totals": {"uniques": 482311, "visits": 1203440, "avg_uniques": 16077, "avg_visits": 40114},
"source_audience": null,
"created_by": { "name": "Jane Doe", "email": "jane.doe@acme.example" },
"project": { "id": 4, "name": "Retail 2025" },
"operator": "AND",
"dataset": [
{ "analysis_type": "WebDomain", "start_date": "01/01/2025", "end_date": "03/31/2025" },
{ "analysis_type": "Apps", "start_date": "01/01/2025", "end_date": "03/31/2025" }
],
"recipe_hash": null,
"normalized_payload": null,
"created_at": "2025-01-01 12:00:00",
"updated_at": "2025-01-10 09:30:00"
}
]
}Estimate Audience Size
POST /api/v2/analyses/audiences/estimate
Answers “how many devices would this audience hold?” without creating an
audience. The request body is identical to
Create Audience - same fields, same
validation, same 422 responses - and the estimate runs the same build
pipeline, so the numbers match what a create with this payload would produce.
Nothing appears in the Audience Manager and no export, cohort, schedule, or
activation is triggered.
The estimate is asynchronous and takes roughly as long as a real audience
build. Poll
GET /api/v2/analyses/audiences/estimate/{id}
until status is completed, blocked, or failed.
Because it runs the same build, an estimate scans the same data a create
would and counts toward your company’s monthly data-scan limit, reported under
the estimate operation type on Usage. When the limit has
been reached the call is refused with the same 422 a create receives, before
anything is queued.
The response carries recipe_hash: a canonical hash of the datasets +
operator recipe. Creating an audience with the identical payload stamps the
same hash on the audience (returned by
Get Audience), proving the created audience
matches the estimated recipe. The name and project_id are not part of the
hash - renaming does not invalidate an estimate.
Auth: bearer token + Accept: application/json + Content-Type: application/json. Rate limit: write bucket (30 requests/min). Optional:
Idempotency-Key header (see below).
Body
The body of Create Audience, unchanged:
name and datasets required, operator required for two dataset blocks,
optional project_id and analyses (checked exactly as on create; an estimate
never runs an analysis, and the flags change neither the estimate nor its
recipe_hash). Every dataset block rule on this page applies verbatim.
curl -X POST "https://console.intuizi.com/api/v2/analyses/audiences/estimate" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"name": "Coffee Buyers NYC (probe)",
"datasets": [{ "type": "Cohorts", "cohort_id": 7 }]
}'Response
201 with the queued estimate. estimate is null until the run completes.
{
"status": "success",
"code": 201,
"message": "Resource created successfully.",
"data": [
{
"id": 12,
"status": "pending",
"name": "Coffee Buyers NYC (probe)",
"recipe_hash": "sha256:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
"normalized_payload": {
"name": "Coffee Buyers NYC (probe)",
"operator": "Single",
"datasets": [{ "cohort_id": 7, "type": "Cohorts" }]
},
"estimate": null,
"status_message": null,
"project_id": null,
"created_at": "2026-08-24 12:00:00",
"updated_at": "2026-08-24 12:00:00"
}
]
}Get Audience Estimate
GET /api/v2/analyses/audiences/estimate/{id}
Retrieves one size estimate with its status and, once completed, the numbers.
status walks pending -> processing -> one of three terminal states:
completed (the estimate object holds the numbers), blocked (the recipe
cannot be answered - estimate.blocked is { code, reason }, e.g.
OUT_OF_COVERAGE with the available date window), or failed
(status_message explains).
On completed, estimate carries: uniques (approximate distinct device
count - the same counting method real audience totals use, with a standard
error of about 2.3%), visits / signals / unique_eips where the dataset
types produce them, the full totals row a create would have shown,
providers (signal providers present in the result), as_of (when the
numbers were computed), query_metrics (runtime and data scanned), method
and exact (how the count was produced), and the echoed canonical
recipe_hash.
Auth: bearer token + Accept: application/json. Rate limit: read bucket
(120 requests/min).
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The estimate id from Estimate Audience Size. |
curl "https://console.intuizi.com/api/v2/analyses/audiences/estimate/12" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"Response
{
"status": "success",
"code": 200,
"message": "Resource fetched successfully.",
"data": [
{
"id": 12,
"status": "completed",
"name": "Coffee Buyers NYC (probe)",
"recipe_hash": "sha256:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
"normalized_payload": {
"name": "Coffee Buyers NYC (probe)",
"operator": "Single",
"datasets": [{ "cohort_id": 7, "type": "Cohorts" }]
},
"estimate": {
"uniques": 482311,
"visits": 1203440,
"signals": null,
"unique_eips": null,
"number_of_days": 30,
"method": "approx_distinct",
"exact": false,
"as_of": "2026-08-24T12:34:56Z",
"providers": ["<provider-bid>"],
"query_metrics": { "total_queries": 9, "total_data_scanned_bytes": 1073741824, "total_runtime_ms": 412000 },
"canonical_hash": "sha256:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
"totals": { "uniques": 482311, "visits": 1203440 },
"blocked": null
},
"status_message": null,
"project_id": null,
"created_at": "2026-08-24 12:00:00",
"updated_at": "2026-08-24 12:07:00"
}
]
}A blocked estimate keeps status: "blocked" and explains itself:
{
"estimate": {
"uniques": null,
"blocked": {
"code": "OUT_OF_COVERAGE",
"reason": "No POI signal data is available for 2020-01-01..2020-02-01. POI data is available 2024-01 to 2026-07. Adjust the date range to overlap the available window."
}
}
}Delete Audience
POST /api/v2/analyses/audiences/delete-by-id
Soft-deletes an audience and queues the downstream cleanup.
Auth: bearer token + Accept: application/json + Content-Type: application/json. Rate limit: write bucket (30 requests/min).
Body
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The audience id to delete. Must be owned by your company. |
curl -X POST "https://console.intuizi.com/api/v2/analyses/audiences/delete-by-id" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "id": 88 }'Response
{
"status": "success",
"code": 200,
"message": "Resource deleted successfully.",
"data": []
}Create Lookalike Audience
POST /api/v2/analyses/audiences/create-lookalike
Builds a Lookalike Model from a completed seed audience. The result is a new
audience (is_lookalike: true) that goes through the normal polling
lifecycle - poll
GET /api/v2/analyses/audiences/{id} for its
status. Lookalike Models are a gated feature: accounts without the
capability receive 403 - it requires additional permissions which need to be
approved by your Account Manager. The seed audience must be a Completed
audience owned by your company, must not itself be a lookalike, and must hold
at least 1,000 devices by default.
Auth: bearer token + Accept: application/json + Content-Type: application/json. Rate limit: write bucket (30 requests/min by default).
Optional: Idempotency-Key header (see Idempotency).
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the Lookalike Model and its result audience. |
source_audience_id | integer | Yes | The seed audience id this model learns from. Must be owned by your company, Completed, not itself a lookalike, and hold at least 1,000 devices by default. |
config | object | Yes | Model configuration - see the fields below. |
config.target_size | integer | Yes | How many devices the output audience should contain. 1 to 4,000,000 by default. |
config.geo.countries | string[] | Yes | Countries the candidate universe is restricted to (at least one). Candidates come from Origin data, which covers only some countries, and the create accepts any country code: a run in which none of the countries has Origin data fails after it is created, and when only some do, the others are left out of the model without an error. Start from the Origin list, GET .../reference/common/countries?datasetType=Origin. |
config.geo.states | string[] | No | States the candidate universe is restricted to. |
config.signals | string[] | Yes | Data families the model learns from (at least one): poi, apps, demographics, transactions, profile_attributes. They do not all describe the same thing - see Data families below. (web and ctv are withdrawn; requests naming them are rejected with 422.) |
config.exclude_seed_devices | boolean | Yes | When true, the seed audience’s own devices are removed from the output audience. |
config.contrast_audience_id | integer | No | A second completed audience used as negative examples the model contrasts against. Must belong to your company, be Completed, not be a lookalike, and differ from source_audience_id. Omit for an automatic geo-matched sample. |
config.expand_eids | boolean | Yes | When true, each output device is expanded across its linked identifiers. |
Data families
The families differ in what they observe and over what period. Both matter when you read a model’s results, so they are worth knowing before you choose.
| Family | What it observes | Grain | Window |
|---|---|---|---|
poi | Physical visits to places | Device | Last full calendar month |
apps | Mobile app usage | Device | Last full calendar month |
demographics | Age, income, gender, marital status | Device | Current state, no window |
transactions | Card transaction behaviour | Device | One finalized calendar month |
profile_attributes | Household/person profile of the device’s ONE primary person, read from two catalogs at once: the AA consumer layer (household income and net worth, investments, home ownership, dwelling, education, generation, marital status, household composition, occupation) and the Vision Marketing layer (age band, household size, income band, home ownership and value, education, children, lifestyle flags) - one person per device | Device | Current state, latest quarterly profile refresh |
web | Web browsing (withdrawn; models built before 2026-08-29 still report it) | Household | Trailing 7 complete days |
web is household-derived, which is the one asymmetry to keep in mind.
Browsing is observed against a household’s IP address and attributed to the
devices in that household, capped at the few devices most associated with the
address. A device’s web activity therefore means “browsing seen at this
device’s household”, not “browsing done by this device”. Every other family is
observed on the device itself.
web also reads a trailing 7 days rather than a calendar month, because
browsing is a recency signal. Two families in one model can describe different
periods.
Selecting more families is not automatically better. A family only helps when the seed audience’s own devices are covered by it, and coverage varies a great deal between audiences. The completed model reports how much of each cohort each family actually reached, so you can see what a given run drew on.
Reading a completed model back returns a feature_families object recording
exactly that:
"feature_families": {
"registry_version": "2026-08-27.1",
"included": [
{
"name": "web",
"period": "2026-08-21..2026-08-27",
"coverage": {
"seed": 28.85,
"candidates": 60.2,
"devices_with_signal": 978047
}
}
]
}period is the exact date range the family read, which is what makes a run
reproducible for families whose window moves. Families measured over a fixed
calendar month omit it - the table above already says what window each family
uses.
coverage reports the share of your seed devices and of the
candidates (the pool the model scored) that carried the family’s signal.
The percentages are the useful part when a model underperforms: a family that
reached only a small share of your seed had little to learn from, whatever its
coverage of the wider candidate pool. feature_families is
null for audiences that are not lookalike models, and for models created
before this was recorded.
The read also names the seed the model was built from, so you can read the seed back with Get Audience - for example to see which datasets and date windows it holds:
"is_lookalike": true,
"source_audience": { "id": 14988, "name": "Coffee Buyers NYC" }| notification | boolean | No | Whether to send an email on completion. Defaults to true. |
curl -X POST "https://console.intuizi.com/api/v2/analyses/audiences/create-lookalike" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: <UNIQUE_KEY>" \
-d '{
"name": "API Lookalike",
"source_audience_id": 14988,
"config": {
"target_size": 100000,
"geo": { "countries": ["USA"], "states": [] },
"signals": ["poi", "apps"],
"exclude_seed_devices": true,
"contrast_audience_id": null,
"expand_eids": false
}
}'Response
The create response is the freshly queued result audience (status Initiating).
{
"status": "success",
"code": 201,
"message": "Resource created successfully.",
"data": [
{
"id": 15021,
"name": "API Lookalike",
"status": { "id": 100, "name": "Initiating" },
"is_lookalike": true,
"source_audience_id": 14988
}
]
}Cancel Lookalike
POST /api/v2/analyses/audiences/cancel-lookalike
Requests cooperative cancellation of an in-flight Lookalike Model run: the
job checks the cancellation flag at its next checkpoint and stops there
rather than being killed immediately. A finished run cannot be cancelled.
Until the run reaches that checkpoint the audience keeps reading 108
Modeling. When it stops, the audience ends at 400 Error, which is final and
never reaches 104, and an
audience.failed webhook is sent.
Audience Manager shows the status as Cancelled on request. A cancel that
arrives once the result is already being published is ignored, and the run
completes at 104.
Auth: bearer token + Accept: application/json + Content-Type: application/json. Rate limit: write bucket (30 requests/min by default).
Body
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The lookalike audience id to cancel - the id returned by Create Lookalike Audience. |
curl -X POST "https://console.intuizi.com/api/v2/analyses/audiences/cancel-lookalike" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "id": 15021 }'Response
{
"status": "success",
"code": 200,
"message": "Cancellation requested.",
"data": []
}