Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.interchange.io/llms.txt

Use this file to discover all available pages before exploring further.

Overview

A property list is a named, advertiser-scoped collection of typed identifiers (websites, mobile apps, CTV apps) used to shape where a brand’s media runs. Lists carry a purpose of either include (only buy on these properties) or exclude (never buy on these properties). Once created, lists are linked to the brand’s targeting profile and flow into every product discovery and media buy as part of the ADCP target_overlay. Property lists are a buyer-curated concept. They are owned by your advertiser, validated against the AAO property registry, and pushed to sales agents as a PropertyListReference that the agent resolves on demand.

Include lists

Restrict targeting to a hand-picked allow-list (e.g., a curated PMP of premium publishers).

Exclude lists

Block specific domains across all of an advertiser’s campaigns (e.g., a brand-safety blocklist).

Concept

Each list stores a set of typed identifiers that are normalized, deduped, and resolved through two systems:
  1. AAO registry — the cross-publisher Ad Context registry used to confirm a property is a real, identified entry.
  2. Local property catalog — Scope3’s mapping of identifiers to targetable Property records used by sales agents.
Submitted identifiers land in one of three buckets, surfaced in every create/update response as a resolutionSummary:
BucketMeaningTargets?
resolvedCountMapped to a local Property recordYes
registeredCountKnown to AAO but no local property yetNot yet — will become targetable as catalog catches up
unresolvedCountNot found anywhereNo — silently skipped
A single list can hold up to 100,000 identifiers per request. The service chunks large inputs server-side against the AAO registry (which itself caps at 10,000 domains per call) and returns a single resource with the full resolution summary.

Identifier types

Property lists accept AdCP-aligned typed identifiers. Pass a typed array via identifiers: [{type, value}], or use the domains: string[] shorthand when every entry is a website domain.
TypeResolves viaExample value
domainDomain.domain (SITE)nytimes.com
subdomainDomain.domain (SITE)news.example.com
ios_bundleApp.bundle (Apple App Store)com.facebook.katana
android_packageApp.bundle (Google Play)com.facebook.katana
apple_tv_bundleApp.bundle (Apple App Store)com.netflix.Netflix
bundle_id (generic fallback)App.bundle (any store)com.example.app
apple_app_store_idDomain.domain (APPLE_APP_STORE)284882215
google_play_idDomain.domain (GOOGLE_PLAY_STORE)com.example.app
roku_store_idDomain.domain (ROKU)12
fire_tv_asinDomain.domain (AMAZON)B00X4WHP5E
samsung_app_idDomain.domain (SAMSUNG)G19173000091
A single mobile app can appear in a property list under multiple identifier types (e.g. ios_bundle AND apple_app_store_id); each resolves independently against the AAO registry / local catalog.
domains: ["nytimes.com"] is exactly equivalent to identifiers: [{ "type": "domain", "value": "nytimes.com" }]. You can pass both fields in the same request — they’re concatenated and deduplicated.
Read-side normalization. apple_tv_bundle and ios_bundle share the same backing column (App.bundle with appStore=APPLE_APP_STORE), so an apple_tv_bundle write reads back as ios_bundle on subsequent GET/list responses. The generic bundle_id fallback likewise normalizes to the resolved app row’s store-typed form (ios_bundle or android_package). Submit the type that best matches the AdCP property registry; expect the response to carry the canonical store-typed form.

Endpoints

All buyer endpoints below are mounted under https://api.interchange.io/api/v2/buyer. The GET /lists/:listId resolution endpoint is mounted at the app root (no /api/v2/buyer or /api/v2/storefront prefix) per ADCP convention.
MethodPathPurpose
GET/api/v2/buyer/advertisers/:advertiserId/property-listsList lists for an advertiser
POST/api/v2/buyer/advertisers/:advertiserId/property-listsCreate a list
GET/api/v2/buyer/advertisers/:advertiserId/property-lists/:listIdGet one list
PUT/api/v2/buyer/advertisers/:advertiserId/property-lists/:listIdReplace a list’s domains and/or name
DELETE/api/v2/buyer/advertisers/:advertiserId/property-lists/:listIdArchive a list
POST/api/v2/buyer/property-lists/checkValidate a candidate domain set without creating a list
GET/lists/:listIdHigh-cardinality public read used by sales agents (HMAC token auth, mounted at app root)
All propertyList-returning responses use the { propertyList } wrapper. List endpoints return { propertyLists, total }.

How to use

Create an include list

Domains-only shorthand:
curl -X POST 'https://api.interchange.io/api/v2/buyer/advertisers/12345/property-lists' \
  -H 'Authorization: Bearer scope3_<your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Q1 UK Premium",
    "purpose": "include",
    "domains": ["nytimes.com", "bbc.co.uk", "cnn.com"],
    "filters": {
      "channels_any": ["display", "olv"],
      "countries_all": ["GB"]
    }
  }'
Mixed web + mobile + CTV:
curl -X POST 'https://api.interchange.io/api/v2/buyer/advertisers/12345/property-lists' \
  -H 'Authorization: Bearer scope3_<your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Cross-screen premium",
    "purpose": "include",
    "identifiers": [
      { "type": "domain", "value": "nytimes.com" },
      { "type": "ios_bundle", "value": "com.nytimes.NYTimes" },
      { "type": "android_package", "value": "com.nytimes.android" },
      { "type": "apple_app_store_id", "value": "284862083" },
      { "type": "roku_store_id", "value": "12" }
    ]
  }'
Response:
{
  "propertyList": {
    "listId": "42",
    "name": "Cross-screen premium",
    "purpose": "include",
    "identifiers": [
      { "type": "domain", "value": "nytimes.com" },
      { "type": "ios_bundle", "value": "com.nytimes.NYTimes" },
      { "type": "android_package", "value": "com.nytimes.android" }
    ],
    "unresolvedIdentifiers": [
      { "type": "apple_app_store_id", "value": "284862083" },
      { "type": "roku_store_id", "value": "12" }
    ],
    "registeredIdentifiers": [],
    "domains": ["nytimes.com"],
    "unresolvedDomains": [],
    "registeredDomains": [],
    "propertyCount": 14,
    "resolutionSummary": {
      "totalRequested": 5,
      "resolvedCount": 3,
      "registeredCount": 0,
      "unresolvedCount": 2,
      "resolutionRate": 0.6
    },
    "createdAt": "2026-04-25T10:30:00.000Z",
    "updatedAt": "2026-04-25T10:30:00.000Z"
  }
}
Response fields
  • identifiers — typed {type, value}[] actually resolved to local Property rows. Persisted as catalog membership.
  • unresolvedIdentifiers — submitted identifiers with no matching local Property record. Transient — see persistence note below.
  • registeredIdentifiers — identifiers found in the AAO registry but not yet locally targetable. Today only domain entries can land here. Transient.
  • domains / unresolvedDomains / registeredDomains — convenience views of the above filtered to type: "domain". App identifiers are not in these.
  • resolutionSummary — counts and resolutionRate (0..1) over the deduplicated, normalized input.
unresolvedIdentifiers and registeredIdentifiers are transient output of the resolution call, not persisted state. They appear on create/update responses, then drop on subsequent GETs and on name-only PUTs. Only identifiers (the resolved set) is persisted on the list. Re-submit the identifier set on a PUT to re-surface them.

Update a list

A PUT replaces the full identifier set. Active media buys that reference this list are then notified — see Cascade behavior. You can pass domains, identifiers, or both:
curl -X PUT 'https://api.interchange.io/api/v2/buyer/advertisers/12345/property-lists/42' \
  -H 'Authorization: Bearer scope3_<your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "identifiers": [
      { "type": "domain", "value": "nytimes.com" },
      { "type": "ios_bundle", "value": "com.nytimes.NYTimes" }
    ]
  }'
The update response includes resolutionSummary and cascadeSummary whenever identifiers change. A name-only PUT returns neither.

Validate before you commit

Use POST /api/v2/buyer/property-lists/check to lint a candidate identifier set against curation rules without creating anything:
curl -X POST 'https://api.interchange.io/api/v2/buyer/property-lists/check' \
  -H 'Authorization: Bearer scope3_<your_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "identifiers": [
      { "type": "domain", "value": "nytimes.com" },
      { "type": "domain", "value": "duplicate.com" },
      { "type": "domain", "value": "duplicate.com" },
      { "type": "ios_bundle", "value": "com.facebook.katana" }
    ]
  }'
The response groups entries into action buckets:
BucketMeaning
okClean — safe to include
modifyCanonicalized (e.g., WWW.example.comexample.com)
removeDrop — duplicate or blocked
assessManual review recommended. All non-domain identifiers (mobile/CTV) land here — AAO does not currently check them.
Each bucket entry carries an identifier: { type, value } field that mirrors the input — use it to disambiguate types. reportId (plus reportIds[] when domain input is chunked) is returned only when at least one domain was submitted. Bundles-only and store-IDs-only requests return no report IDs since no AAO call was made.

Cascade behavior

When you PUT an include list, every active media buy whose advertiser references the list is notified via ADCP update_media_buy so the sales agent can refresh its cached property set. The update response surfaces this with a cascadeSummary:
{
  "cascadeSummary": {
    "totalMediaBuys": 4,
    "updatedCount": 3,
    "failedCount": 1
  }
}
The cascade is best-effort and applies to include lists only — the ADCP target_overlay.property_list reference carries include semantics. Cascade failures do not roll back the list update; the database is the source of truth and per-media-buy errors are logged for retry.
Per-media-buy fan-out is bounded (concurrency 5) so a large advertiser cannot thunder a single sales agent.

Resolution endpoint

Sales agents resolve a PropertyListReference by calling GET https://api.interchange.io/lists/:listId with an HMAC bearer token that Scope3 mints when it embeds the reference in a request. This endpoint is mounted at the app root (no /api/v2/buyer or /api/v2/storefront prefix) per ADCP convention. The endpoint returns ADCP GetPropertyListResponse shape (not the standard { data, error, meta } envelope):
{
  "list": { "list_id": "42", "name": "Cross-screen premium" },
  "identifiers": [
    { "type": "domain", "value": "nytimes.com" },
    { "type": "ios_bundle", "value": "com.nytimes.NYTimes" },
    { "type": "android_package", "value": "com.nytimes.android" }
  ],
  "resolved_at": "2026-04-25T10:30:00.000Z",
  "cache_valid_until": "2026-04-26T10:30:00.000Z"
}
Agents are expected to cache the response until cache_valid_until (24 h).

Best practices

  • Always inspect resolutionSummary. Any non-zero unresolvedCount indicates identifiers that will not target — surface them to the user before going live.
  • Submit multiple identifier types for the same app. A mobile app is more reliably resolved when you include both its ios_bundle and android_package (and, where available, apple_app_store_id / google_play_id). Each is resolved independently against the AAO registry.
  • Prefer one large list over many small ones. A 100k-identifier list is cheaper than 100 lists of 1k identifiers because each list creates its own SmartPropertyList link.
  • Use filters.channels_any to scope a list. Without it, the list applies across all of the brand’s targeting profiles. With it, you can keep display/OLV separate from CTV.
  • Treat updates as full replacements. PUT replaces the entire identifier set; there is no incremental add/remove. Re-send the union you want stored.
  • Validate before bulk import. Run POST /api/v2/buyer/property-lists/check on the raw input first, especially when assembling a list from spreadsheets or third-party feeds.
  • Avoid touching include lists during high-traffic windows. Cascading notifies every active media buy on the advertiser; schedule large updates for off-peak times when possible.

Limits

LimitValue
Identifiers per request (create / update / check)100,000
Domains per AAO registry call (auto-chunked)10,000
Cascade concurrency per update5 media buys at a time
List name length1–255 characters
Cache TTL on resolved list24 hours