Create an Audience
An audience is a definition of who you want to reach. You build it against one or two datasets by selecting filter values that you read from reference data first. This guide covers the single create endpoint, the create-then-poll flow, the fields each dataset type accepts, combining two datasets with an operator, and the optional crossvisitation and cross purchase analyses.
There is one create endpoint:
POST /api/v2/analyses/audiences/create
An audience holds one or two datasets. Each dataset travels in the body as an
entry in a datasets array with a type - fetch the accepted values from
Get Dataset Types.
When you supply two datasets you combine them with an operator
(AND, OR, or NOTIN); a single dataset takes no operator. The exact,
field-level contract is in the
API Reference - Audiences; this guide is the
narrative.
Prerequisites
- A bearer token (Authentication).
- The reference values you want to target. Read them first with Working with Reference Data - every filter below is populated from a reference read, so you send the exact values the builder expects. The per-type sections link each field to its read.
The create flow
- Authenticate and get a bearer token.
- Build the dataset body - pick each dataset’s
type, the window (start_date/end_datefor all types except Cohorts and Demographics), and the filters you want from reference data. With two datasets, also pick anoperator. - POST the body to
/api/v2/analyses/audiences/create. The response returns the new audience id immediately, in status100Initiating. - Poll
GET /api/v2/analyses/audiences/{id}until the lifecycle status reaches104Completed.
The request 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). |
analyses | object | No | The frequency analyses: frequency (POI, with frequency_day_part), apps_frequency (Apps) and web_frequency (WebDomain) run the analysis the activation preview needs; gated and tied to the dataset type - see Frequency analyses. |
Each datasets[i] block always carries a type. Except for Cohorts and
Demographics, it also carries a start_date and end_date. The remaining
fields depend on the type.
The accepted type values are the dataset types your company is entitled to,
fetchable from
GET /api/v2/analyses/reference/common/dataset-types.
Send only the filters you want - on each type they are optional on their own; you just need enough to define a meaningful population.
Combining two datasets
To target the intersection, union, or exclusion of two populations, supply two
dataset blocks and an operator:
AND- people who match both datasets.OR- people who match either dataset.NOTIN- people who match the first dataset but not the second.
The operator is required whenever you send two datasets, and is rejected if you
send only one. Both datasets are validated exactly the same way (each dataset’s ids must exist). A second dataset that is
present but missing its type is rejected with 422.
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",
"iab_category_codes": [1, 4],
"web_domains": ["example.com"],
"device_types": ["Mobile"],
"browsers": ["Chrome"],
"languages": ["en"],
"location": { "countries": ["USA"] }
}
]
}'A two-dataset request
This example combines a WebDomain dataset with an Apps dataset using AND, so
the audience is the people who match both:
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": "Auto-intenders who also run finance apps",
"operator": "AND",
"datasets": [
{
"type": "WebDomain",
"start_date": "2026-07-01",
"end_date": "2026-07-28",
"iab_category_codes": [1, 4],
"location": { "countries": ["USA"] }
},
{
"type": "Apps",
"start_date": "2026-07-01",
"end_date": "2026-07-28",
"categories": [12],
"location": { "countries": ["USA"] }
}
]
}'Idempotency-Key header is optional and you generate it yourself - any
unique string (a UUID v4 is typical), one per logical create. Reuse the same key
only when retrying the exact same request: the retry replays the original
response (Idempotency-Replayed: true) instead of double-creating the audience;
the same key with a different body returns 409.The response
The create response is the freshly queued audience, in status 100 Initiating
with results_count 0. The standard { status, code, message, data }
envelope wraps it.
{
"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,
"results_count": 0,
"created_at": "2025-01-01 12:00:00"
}
]
}Dataset fields by type
Every field below is optional unless marked otherwise. The fields backed by a reference catalog link to the read that returns their valid values - fetch those first, then pass the values you collected.
Fields common to all types
These travel directly on each datasets[i] block (except where a type opts out,
noted per section).
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | The dataset type. Fetch the types your company is entitled to from Get Dataset Types - a type not enabled for your account is rejected with 422. |
start_date | string (Y-m-d) | Yes (except Cohorts and Demographics) | Window start date. |
end_date | string (Y-m-d) | Yes (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 and Transactions) | A { countries[], states[], cities[], dmas[], zipcodes[] } block. countries come from GET /api/v2/analyses/reference/common/countries; states cascade from countries via GET /api/v2/analyses/reference/common/states; cities cascade from states via GET /api/v2/analyses/reference/common/cities; dmas (POI and Origin only) come from GET /api/v2/analyses/reference/common/dmas. |
Cohorts takes neither dates nor location. Apps, Demographics,
Deidentified and ProfileAttributes read
location.countries only; WebDomain
and CTV read the full location block. POI requires
location.countries and also reads states, cities, dmas and zipcodes.
Origin requires location.countries and reads the same states,
cities, dmas and zipcodes; its window is widened to whole Monday-to-Sunday
weeks.
AffinityTransactions is United States only: location.countries is optional
there and it reads states, cities and zipcodes; its recency end_date
cannot run past the most recent fully-settled purchase week (the latest Sunday
at least 11 days before today, UTC, which advances each Thursday). The
crosspurchase analysis reads the same purchase data and shares that same
end-date cap. WebDomain reads archive-limited visitation data: its
start_date must fall within the last 45 days of available data, and an
earlier date is rejected with 422.
Demographics takes no dates and no signal providers.
ProfileAttributes covers whole quarters inside a
delivered window.
Web Domain
Targets people by the domains they visit, plus their device and location. Set
type to WebDomain.
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 /api/v2/analyses/reference/web/iab-categories (and subcategories from GET /api/v2/analyses/reference/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 /api/v2/analyses/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 /api/v2/analyses/reference/web/ref-domains. |
device_types | string[] | No | Web device type names. Fetch valid values from GET /api/v2/analyses/reference/web/device-types. |
device_makes | string[] | No | Web device make names. Fetch valid values from GET /api/v2/analyses/reference/web/device-makes. |
device_oses | string[] | No | Web device OS names. Fetch valid values from GET /api/v2/analyses/reference/web/device-oses. |
browsers | string[] | No | Web browser names. Fetch valid values from GET /api/v2/analyses/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). |
Connected TV
Targets people by the streaming content and devices they use. Set type to
CTV. CTV filters are matched by name, not numeric id.
| Field | Type | Required | Description |
|---|---|---|---|
ctv_vendor_names | string[] | No | CTV vendor names. Fetch valid values from GET /api/v2/analyses/reference/ctv/vendors. |
ctv_content_type_names | string[] | No | CTV content type names. Fetch valid values from GET /api/v2/analyses/reference/ctv/content-types. |
ctv_content_genre_names | string[] | No | CTV content genre names. Fetch valid values from GET /api/v2/analyses/reference/ctv/content-genres. |
ctv_channel_names | string[] | No | CTV channel names. Fetch valid values from GET /api/v2/analyses/reference/ctv/channel-names. |
iab_codes | array | No | IAB codes. Fetch valid values from GET /api/v2/analyses/reference/web/iab-categories. |
ctv_device_types | string[] | No | CTV device type names. Fetch valid values from GET /api/v2/analyses/reference/ctv/device-types. |
ctv_device_makes | string[] | No | CTV device make names. Fetch valid values from GET /api/v2/analyses/reference/ctv/device-makes. |
ctv_device_oses | string[] | No | CTV device OS names. Fetch valid values from GET /api/v2/analyses/reference/ctv/device-oses. |
ctv_connection_types | string[] | No | CTV connection type names. Fetch valid values from GET /api/v2/analyses/reference/ctv/connection-types. |
ctv_isps | string[] | No | CTV ISP names. Fetch valid values from GET /api/v2/analyses/reference/ctv/isps. |
ctv_series | string[] | No | CTV series names. Fetch valid values from GET /api/v2/analyses/reference/ctv/series. |
Cohorts
Reuses one of your own completed cohorts as an audience. Set type to Cohorts.
Cohorts are company-scoped: you can only target a completed cohort that
belongs to your company. This type takes no dates and no location.
| Field | Type | Required | Description |
|---|---|---|---|
cohort_id | integer | Yes | A completed cohort id owned by your company. Fetch valid ids from GET /api/v2/analyses/reference/cohorts/get-cohorts. |
Apps
Targets people by the mobile apps they have and the categories those apps belong
to. Set type to Apps. Apps reads location.countries only.
| Field | Type | Required | Description |
|---|---|---|---|
app_ids | integer[] | At least one of categories / taxonomies / bundle_ids / app_ids | App ids to target. Fetch valid ids from GET /api/v2/analyses/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 /api/v2/analyses/reference/apps/bundle-ids. |
categories | array | At least one of categories / taxonomies / bundle_ids / app_ids | App category ids. Fetch valid values from GET /api/v2/analyses/reference/apps/categories. |
taxonomies | array | At least one of categories / taxonomies / bundle_ids / app_ids | App taxonomy ids. Fetch valid values from GET /api/v2/analyses/reference/apps/taxonomies. |
device_os | string[] | No | App device OS values. Fetch valid values from GET /api/v2/analyses/reference/apps/os. |
refine | object | No | Post-build refinement: keep only the most active devices. Permission-gated, single-dataset audiences only - see Refine. |
App tags narrow the targeted set; fetch valid values from GET /api/v2/analyses/reference/apps/tags.
Apps location supports countries only: sending location.states,
location.cities, location.dmas, or location.zipcodes on an Apps dataset
is rejected with 422.
POI
Targets people by the points of interest (POIs) they physically visited. Set
type to POI. The POI catalogs form a cascade - pick segments, use them to
read categories, categories to read brands, and brands to read individual
locations:
segments -> categories (?segments[]) -> brands (?categories[]) -> locations (?brands[])Unlike the other dataset types, POI requires location.countries (at least
one country). The dataset also accepts an optional time-of-day window
(time_limits) and a distance radius (distance_limits).
| Field | Type | Required | Description |
|---|---|---|---|
categories | integer[] | At least one of categories / analysisdata / locations | POI category ids. Fetch valid values from GET /api/v2/analyses/reference/poi/categories (cascades from segments read via GET /api/v2/analyses/reference/poi/segments). |
analysisdata | integer[] | At least one of categories / analysisdata / locations | POI brand ids. Fetch valid values from GET /api/v2/analyses/reference/poi/brands (cascades from categories). |
locations | array | At least one of categories / analysisdata / locations | POI location identifiers. Fetch candidates from GET /api/v2/analyses/reference/poi/locations (cascades from brands). How the values are interpreted is set by 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. |
signal_providers | string[] | Yes | BID values identifying the signal source. Fetch valid values from GET /api/v2/analyses/reference/common/signal-providers. |
location.countries | string[] | Yes | Country codes (at least one). Fetch from GET /api/v2/analyses/reference/common/countries. |
location.states | string[] | No | State codes. Cascade from countries via GET /api/v2/analyses/reference/common/states. |
location.cities | string[] | No | City names. Cascade from states via GET /api/v2/analyses/reference/common/cities. |
location.dmas | string[] | No | DMA market labels. Fetch from GET /api/v2/analyses/reference/common/dmas. |
location.zipcodes | string[] | No | ZIP codes. Cascade from cities via GET /api/v2/analyses/reference/common/zipcodes (paginated). |
time_limits | object | No | { process: boolean, start: 0-23, end: 0-23 } - restrict to an hour-of-day window when process is true. |
day_limits | object | No | { process: boolean, days: integer[] } - restrict to days of the week when process is true; ISO numbering (1 = Monday .. 7 = Sunday). |
distance_limits | object | No | { process: boolean, distance: number, unit: "miles" | "kilometers" } - restrict to visits within a radius 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.
Transactions
Targets people by what they actually bought. Set type to
AffinityTransactions. The purchase catalogs form a cascade - pick
categories, use them to read sub-categories, and both to read brands:
categories -> subcategories (?categories[]) -> brands (?categories[], ?subcategories[])At least one categories or brands value is required - without one the
dataset has no purchase filter. Sub-categories are the merchant category
description strings the sub-categories read returns (not ids); picked without
any brands, they are resolved to the brands they cover.
Affinity purchase data is United States only, so location.countries is
optional here and always stored as ["USA"]. Sending any other country code is
rejected with 422, as is location.dmas - this type reads location.states,
location.cities and location.zipcodes only.
| Field | Type | Required | Description |
|---|---|---|---|
categories | integer[] | At least one of categories / brands | Affinity purchase category ids. Fetch valid values from GET /api/v2/analyses/reference/affinity-transactions/categories. |
brands | string[] | At least one of categories / brands | Affinity brand id strings. Fetch valid values from GET /api/v2/analyses/reference/affinity-transactions/brands (cascades from categories and sub-categories). |
subcategories | string[] | No | Sub-category strings cascading from categories. Fetch valid values from GET /api/v2/analyses/reference/affinity-transactions/subcategories. |
incomes | string[] | No | Income bands. Fetch valid values from GET /api/v2/analyses/reference/affinity-transactions/incomes. |
ages | string[] | No | Age bands. Fetch valid values from GET /api/v2/analyses/reference/affinity-transactions/ages. |
genders | string[] | No | Gender values. Fetch valid values from GET /api/v2/analyses/reference/affinity-transactions/genders. |
ethnicities | string[] | No | Ethnicity values. Fetch valid values from GET /api/v2/analyses/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). |
{
"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
Targets people by their household demographic attributes. Set type to
Demographics. The four dictionaries are flat - there is no cascade - and at
least one of them must carry a selection, otherwise the dataset has no filter.
This type carries no date window and no signal providers: sending
start_date, end_date or signal_providers is rejected with 422. Its
location supports countries only (at least one is required), 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 /api/v2/analyses/reference/demographics/genders. |
ages | string[] | At least one of genders / ages / marital_statuses / incomes | Age ranges. Fetch valid values from GET /api/v2/analyses/reference/demographics/ages. |
marital_statuses | string[] | At least one of genders / ages / marital_statuses / incomes | Marital status values. Fetch valid values from GET /api/v2/analyses/reference/demographics/marital-statuses. |
incomes | string[] | At least one of genders / ages / marital_statuses / incomes | Income ranges. Fetch valid values from GET /api/v2/analyses/reference/demographics/incomes. |
location.countries | string[] | Yes | Country codes (at least one). Fetch valid values from GET /api/v2/analyses/reference/common/countries. |
{
"type": "Demographics",
"genders": ["F"],
"ages": ["25-34", "35-44"],
"incomes": ["100k-150k"],
"location": { "countries": ["USA"] }
}Deidentified
Delivers the deidentified signals themselves for a country and date window,
rather than a targeted device list. Set type to Deidentified. Instead of
filters it takes fields: which signal fields the delivery carries.
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 /api/v2/analyses/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.
| Field | Type | Required | Description |
|---|---|---|---|
fields | object | No | Which signal fields the delivery carries, keyed by group. Fetch the fields and their groups from GET /api/v2/analyses/reference/deidentified/fields. |
signal_providers | string[] | Yes | BID values identifying the signal source (at least one). Fetch valid values from GET /api/v2/analyses/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). Fetch valid values from GET /api/v2/analyses/reference/common/countries. |
{
"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"] }
}Profile Attributes
Targets people by the profile attributes they carry. Set type to
ProfileAttributes. 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 -
combined with AND, so a device must match every row.
The attribute catalogs form a three-level cascade - pick a category, use it to read the keys under it, and both to read that key’s values:
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.
Its location supports countries only, so location.states, location.cities,
location.zipcodes and location.dmas are rejected.
Profile attribute data is delivered quarterly. start_date and end_date must
fall inside the delivered window published by
GET /api/v2/analyses/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 /api/v2/analyses/reference/profile-attributes/categories. |
profile_attributes[].key | string | Yes | An attribute key under that category. Fetch valid values from GET /api/v2/analyses/reference/profile-attributes/keys (cascades from categories). |
profile_attributes[].value_ids | integer[] | Yes | Value ids of that key (at least one). Fetch valid values from GET /api/v2/analyses/reference/profile-attributes/values (cascades from categories and the key). |
signal_providers | string[] | Yes | BID values identifying the signal source (at least one). Fetch valid values from GET /api/v2/analyses/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. |
{
"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
Targets people by their home location - where a device originates - rather
than by the places it visited. Set type to Origin. 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 narrows that resolved home location.
Its only filters are geographic: location.countries is required, and
states, cities, dmas and zipcodes are optional. signal_providers is
required as for the other dated types.
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 /api/v2/analyses/reference/common/countries
with ?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). Fetch valid values from GET /api/v2/analyses/reference/common/signal-providers with ?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. Fetch valid values from GET /api/v2/analyses/reference/common/countries with ?datasetType=Origin. |
location.states | string[] | No | State codes. Fetch valid values from GET /api/v2/analyses/reference/common/states. |
location.cities | string[] | No | City names. Fetch valid values from GET /api/v2/analyses/reference/common/cities. |
location.dmas | string[] | No | DMA labels exactly as returned by GET /api/v2/analyses/reference/common/dmas - the label string, never a numeric code. |
location.zipcodes | string[] | No | ZIP codes. Fetch valid values from GET /api/v2/analyses/reference/common/zipcodes. |
{
"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 audience
POI and Apps datasets accept an optional refine object that 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 applies to single-dataset audiences only - a refine block on
either dataset of a two-dataset audience, or on any other dataset type, is
rejected with 422.
refine block is present and
the feature is not enabled, the request is rejected with 403 - it is 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. |
For example, to keep only the devices in the top 10% by visit frequency, dropping the top 1% as likely bots:
{
"name": "Frequent coffee shop visitors",
"datasets": [{
"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
Crossvisitation narrows the audience to people who physically visited
points of interest (POIs) you select - by category, by brand, or by specific
locations - within a date window and optional time-of-day and distance limits. It
travels in the body as an optional top-level crossvisitation object alongside
datasets.
crossvisitation block
is present and the feature is not enabled, the request is rejected with 403 -
it is never silently ignored. Omitting the block entirely requires nothing.Where the POI ids come from
Pick the POI values from the read-only Dataset Types - POI catalogs - the same source as every other audience-builder field. (Creating and managing the underlying POI data itself is the separate My POI Data surface; see Submit POI Data.)
categoriesare POI category ids. Fetch them fromGET /api/v2/analyses/reference/poi/categories.brandsare POI brand ids. Fetch them fromGET /api/v2/analyses/reference/poi/brands.locationsare identifiers for individual POI locations. Fetch candidates fromGET /api/v2/analyses/reference/poi/locations. The kind of identifier you send is declared bylocation_identifier_type.
Crossvisitation fields
| 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. Their kind is set by location_identifier_type. |
location_identifier_type | string | No | How the locations values 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 /api/v2/analyses/reference/common/countries. |
time_limits | object | No | { process: boolean, start: 0-23, end: 0-23 } - restrict to an hour-of-day window when process is true. |
day_limits | object | No | { process: boolean, days: integer[] } - restrict to days of the week when process is true; ISO numbering (1 = Monday .. 7 = Sunday). |
distance_limits | object | No | { process: boolean, distance: number, unit: "miles" | "kilometers" } - restrict to visits within a radius when process is true. |
A crossvisitation example
Crossvisitation is available only for the POI dataset. This combines a POI
dataset with a crossvisitation block that narrows it to visitors of specific POI
brands within a date window and a distance limit:
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": "Coffee-shop cross visitors",
"datasets": [
{
"type": "POI",
"start_date": "2025-01-01",
"end_date": "2025-03-31",
"signal_providers": ["BID001"],
"categories": [10],
"location": { "countries": ["USA"] }
}
],
"crossvisitation": {
"start_date": "2025-01-01",
"end_date": "2025-03-31",
"poi_level": true,
"filters": ["gps_only"],
"categories": [10],
"brands": [55, 56],
"location": { "countries": ["USA"] },
"distance_limits": { "process": true, "distance": 5, "unit": "miles" }
}
}'GET /api/v2/analyses/audiences/{id} returns the datasets and
operator, not the crossvisitation block. Keep your own copy of what you sent.Cross Purchase
Cross purchase 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 travels in the body as an optional top-level crosspurchase object
alongside datasets. 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.
crosspurchase block is
present and the feature is not enabled, the request is rejected with 403 - it
is never silently ignored. Omitting the block entirely requires nothing.Pick the target values from the read-only Transactions catalogs - they cascade (categories -> subcategories -> brands), and any mix works: at least one target across the three arrays is required.
| 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. |
target_categories | integer[] | At least one of target_categories / target_subcategories / target_brands | Affinity category ids. From GET /api/v2/analyses/reference/affinity-transactions/categories. |
target_subcategories | string[] | At least one of target_categories / target_subcategories / target_brands | Affinity sub-category strings. From GET /api/v2/analyses/reference/affinity-transactions/subcategories. |
target_brands | string[] | At least one of target_categories / target_subcategories / target_brands | Affinity brand id strings. From GET /api/v2/analyses/reference/affinity-transactions/brands. |
For example, to report how a POI audience purchases across dining brands:
{
"name": "Coffee visitors vs dining purchases",
"datasets": [{
"type": "POI",
"start_date": "2025-01-01",
"end_date": "2025-03-31",
"signal_providers": ["BID001"],
"categories": [101],
"location": { "countries": ["USA"] }
}],
"crosspurchase": {
"start_date": "2025-01-01",
"end_date": "2025-02-28",
"target_categories": [1],
"target_brands": ["501"]
}
}Poll until Completed
Audience creation is asynchronous (see The Async Model).
The create response gives you the new audience id; poll it until its lifecycle
status reaches 104 Completed.
curl "https://console.intuizi.com/api/v2/analyses/audiences/<AUDIENCE_ID>" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"100-103,105,108,109- still processing. Poll again shortly.109Visualizing data streams means the audience is drawing the data stream visualizations it opted into, and105DataStreaming comes before104.104Completed - the audience is ready to activate.107Additional Info - the build stopped and will not continue. Stop polling. Audience Manager shows the reason, most often a date range outside the data available for the dataset. Fix the request and create the audience again.4xx- an error state. Stop polling and inspect the response.
See List, Get & Delete for reading and removing audiences, and Read an Audience for the full read response.
Next steps
- Activate an Audience to deliver it once it is Completed.
- Build a Lookalike Model to grow a completed audience into a larger set of similar devices.
Reference
- Reference data: Working with Reference Data
- Dataset concept: Datasets
- Polling and retries: Polling and Rate Limits
- Field-level contract: API Reference - Audiences