create_media_buy targeting overlays for explicit retargeting or suppression.
Audiences are distinct from signals: signals are named targeting dimensions discovered through product signal options, provider-published signal definitions, or get_signals; audiences are data you own and upload. Use audience_include to target only members of an uploaded list. audience_include is a hard constraint — only users on the list are eligible. To find new users similar to an audience (lookalike expansion), describe that intent in your campaign brief — the seller handles expansion strategy. Note: lookalike intent expressed in the brief cannot be verified through the protocol; confirm via seller-side reporting.
Response Time: Upload accepted in ~1–2s. Per-audience matching is asynchronous — the task remains active until matching completes (1–48 hours depending on the seller). Configure push_notification_config to receive a webhook when the audience is ready. Sellers whose ingestion pipeline cannot return per-audience results in the synchronous response (batch ingestion, governance-gated upload, clean-room flows) MAY respond with an operation-level submitted task envelope — see Response shapes.
Request Schema: /schemas/3.1.0-rc.7/media-buy/sync-audiences-request.json
Response Schema: /schemas/3.1.0-rc.7/media-buy/sync-audiences-response.json
Quick Start
Upload a customer list and check its status:Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
account | account-ref | Yes | Account reference. Pass { "account_id": "..." } or { "brand": {...}, "operator": "..." } if the seller supports implicit resolution. |
audiences | Audience[] | No | Audiences to sync. When omitted, the call is discovery-only and returns all existing audiences without modification. |
delete_missing | boolean | No | When true, buyer-managed audiences on the account not in this request are removed (default: false). Does not affect seller-managed audiences. Do not combine with an omitted audiences array or all buyer-managed audiences will be deleted. |
Audience Object
| Field | Type | Required | Description |
|---|---|---|---|
audience_id | string | Yes | Buyer’s identifier for this audience. Used to reference the audience in targeting overlays. |
name | string | No | Human-readable name |
delete | boolean | No | When true, delete this audience from the account entirely. All other fields are ignored. |
add | AudienceMember[] | No | Members to add to this audience |
remove | AudienceMember[] | No | Members to remove from this audience. If the same identifier appears in both add and remove, remove takes precedence. |
consent_basis | string | No | GDPR lawful basis: consent, legitimate_interest, contract, or legal_obligation. Required by some sellers in regulated markets. |
Audience Member
Every member requires anexternal_id (buyer-assigned stable identifier) plus at least one matchable identifier. Hash all values with SHA-256 before sending — normalize emails to lowercase+trim, phone numbers to E.164 format (e.g. +12065551234).
| Field | Type | Description |
|---|---|---|
external_id | string | Required. Buyer-assigned stable identifier for this member (e.g. CRM record ID, loyalty ID). Used for deduplication, removal, and cross-referencing with buyer systems. |
hashed_email | string | SHA-256 hash of lowercase, trimmed email (64-char hex) |
hashed_phone | string | SHA-256 hash of E.164-formatted phone number (64-char hex) |
uids | UID[] | Universal IDs: type (rampid, uid2, maid, etc.) + value |
ext for platform-specific extensions.
Identifier support varies by seller: Check get_adcp_capabilities → media_buy.audience_targeting.supported_identifier_types and media_buy.audience_targeting.supported_uid_types before sending. MAID support is not universal (LinkedIn does not accept MAIDs; iOS IDFA requires App Tracking Transparency consent). The media_buy.audience_targeting.matching_latency_hours range and media_buy.audience_targeting.minimum_audience_size in capabilities are also seller-specific.
Size limit: Payloads are limited to 100,000 members per call across all audiences. For larger lists, chunk into sequential calls using add deltas.
Concurrency: Ensure that calls made to sync_audience are independent of eachother. They may be processed out-of-order. If you need sequential execution, wait for the callback to your configured webhook before making another call.
Response shapes
Responses use discriminated unions — a response has exactly one of three shapes, never mixed: 1. Synchronous success — per-audience results:audiences— Results for each audience on the account, including audiences not in this requestsandbox— Boolean indicating if this response is from sandbox mode (optional)
errors— Array of operation-level errors (auth failure, account not found, invalid request format)
status— Always"submitted"task_id— Handle for polling viatasks/getor receiving a webhook on completionmessage— Optional human-readable explanation of the queue state
audiences array lands on the task completion artifact, not on the submitted envelope. Per-audience asynchronous matching (one audience in processing while the rest of the sync resolves synchronously) belongs on the synchronous success branch with status: "processing" on that item, not on the submitted envelope. Matching latency on the per-audience audience-status enum is the common case; the submitted envelope is for the less-common operation-level async case.
Each audience in success response includes:
| Field | Description |
|---|---|
audience_id | Echoed from request (buyer’s identifier) |
seller_id | Seller-assigned ID in their ad platform |
action | created, updated, unchanged, deleted, or failed |
status | processing, ready, or too_small. Present when action is created, updated, or unchanged; absent when action is deleted or failed. |
uploaded_count | Members submitted in this sync operation (delta, not cumulative). 0 for discovery-only calls. |
total_uploaded_count | Cumulative members uploaded across all syncs. Compare with matched_count to calculate match rate. |
matched_count | Total members matched to platform users across all syncs (cumulative). Populated when status: "ready". |
effective_match_rate | Deduplicated match rate across all identifier types (0–1). A single number for reach estimation. Populated when status: "ready". |
match_breakdown | Per-identifier-type match results. Shows which ID types resolve and at what rate. See match breakdown. |
last_synced_at | ISO 8601 timestamp of the most recent sync. Omitted if the seller does not track this. |
minimum_size | Minimum matched audience size for targeting on this platform. Populated when status: "too_small". |
errors | Per-audience errors (only when action: "failed") |
Match breakdown
When a seller supports per-identifier-type reporting, the response includesmatch_breakdown — an array showing which identity types are resolving and at what rate. This helps buyers decide which identifiers to prioritize in future uploads.
submittedandmatchedare cumulative across all syncs, matchingtotal_uploaded_countsemantics (notuploaded_count).effective_match_rateis deduplicated — a member matched via both email and phone counts once. It will be less than or equal to the sum of per-type match rates.match_rateis server-authoritative — consumers should prefer this value over computing their own from submitted/matched.id_typevalues combine hashed PII types (hashed_email,hashed_phone) with universal ID types (rampid,uid2,id5,euid,pairid,maid).
match_breakdown entirely.
Common Scenarios
Discovery Only
Check status of all existing audiences without making changes. The response includes all audiences on the account — filter byaudience_id to find the one you care about:
Suppression List
Upload a list of existing customers to suppress from acquisition campaigns:Removing Members
Update an audience incrementally — add new members and remove ones that no longer qualify:Deleting an Audience
Remove a specific audience from the account without affecting others. Setdelete: true on the audience object:
delete: true. To delete all buyer-managed audiences at once, use delete_missing: true with an empty audiences array — but be careful, this removes everything.
Using Audiences in a Media Buy
Once an audience isready, reference it by audience_id in create_media_buy targeting overlays. Audience IDs are scoped to the seller account — they cannot be used across sellers.
test=false
Audience Status
Platform matching is asynchronous. Thestatus field reflects the current state:
| Status | Meaning |
|---|---|
processing | Platform is matching uploaded members against its user base. Poll again later — do not create campaigns yet. |
ready | Audience is available for targeting. matched_count is populated. |
too_small | Matched audience is below the platform’s minimum size. minimum_size in the response tells you the threshold. Add more members and re-sync. |
status is present when action is created, updated, or unchanged. It is absent when action is deleted or failed.
Sellers MUST emit too_small whenever matched_count < minimum_size. Returning ready with a matched_count below the platform minimum is non-compliant — buyers rely on the status value as a programmatic signal that targeting will fail, not on post-hoc interpretation of the count.
Webhook (recommended): Configure push_notification_config at the protocol level before uploading. The task stays active while the seller’s platform matches members. When matching completes, the task completes and the webhook fires with the final result — status: "ready" or status: "too_small". Check get_adcp_capabilities → audience_targeting.matching_latency_hours to set realistic expectations (typically 1–48 hours).
Polling fallback: If not using webhooks, poll with discovery-only calls (omit audiences) no more frequently than every 15 minutes. Use tasks/get with the task_id to check task status — the task will be submitted while matching is in progress and completed when the audience is ready or too small.
Agent workflow: Upload with push_notification_config set. Externalize the audience_id and account_id before the session ends. When the webhook fires with status: "ready", resume and proceed to create_media_buy.
Async patterns
Two distinct async patterns — match the right one to the seller’s behavior: Per-audience async matching (common): the sync operation itself resolves synchronously and returns per-audience results immediately. Audiences whose matching is still running come back on the synchronous success response withstatus: "processing". The buyer reconciles terminal state (ready / too_small) via subsequent discovery-only calls or a webhook. This is the case covered by the Audience Status enum above.
Operation-level async (less common): the whole sync is queued — the seller cannot return any per-audience results before responding, because ingestion is batched, governance review gates the upload, or an upstream clean-room flow must settle before matching can start. The response is a submitted envelope:
- Top-level
status: "submitted"withtask_id message— optional human-readable explanation- No
audiencesarray on this envelope
tasks/get or wait for the webhook. The completion artifact carries the audiences array with per-item action/status results; operation-level failures surface as status: "failed" on the task.
See: Webhooks for webhook configuration.
Hashing Requirements
Hash all identifiers with SHA-256 before sending. Normalize first:| Identifier | Normalization | Example |
|---|---|---|
| Lowercase, trim whitespace | alice@example.com → hash | |
| Phone | E.164 format | +12065551234 → hash |
| MAID | No normalization needed | As-is |
test=false
Privacy Considerations
The schema never carries cleartext email or phone — buyers MUST hash before transport. The seller matches by independently hashing its own user data with the same algorithm. Hashed identifiers are pseudonymous PII, not anonymous. Unsalted SHA-256 of an email or phone number is recoverable via precomputed dictionaries of the email and E.164 namespaces, sohashed_email and hashed_phone MUST be treated as PII for retention, consent, access control, and data-subject-request purposes. Do not describe them as “privacy-preserving” in operator documentation or DPAs. See Privacy Considerations.
Buyer obligations: The buyer is responsible for having a lawful basis to process and share audience data, regardless of jurisdiction. Include consent_basis on each audience to communicate the GDPR lawful basis to sellers operating in regulated markets — some sellers require this field for EU audiences.
Data handling: Once uploaded, data processing and retention are governed by your agreement with the seller. Review the seller’s data processing terms before uploading audience data.
Error Handling
| Error Code | Description | Resolution |
|---|---|---|
ACCOUNT_NOT_FOUND | Account does not exist | Verify account_id |
REFERENCE_NOT_FOUND | Audience to remove from doesn’t exist or is not accessible (error.field = audience_id) | Check audience_id or omit remove |
INVALID_HASH_FORMAT | Identifier doesn’t match expected hash format | Verify SHA-256 hex encoding (64 chars, lowercase) |
RATE_LIMITED | Too many sync requests | Retry with exponential backoff; poll no more than every 15 minutes |
CALL_TOO_LARGE | Too many members in payload | Payloads are limited to 100,000 members across all audiences |
Next Steps
- Targeting — Reference audiences in
targeting_overlay.audience_includeandaudience_exclude - create_media_buy — Apply audience targeting to packages
- Conversion Tracking — Track outcomes from audience-targeted campaigns