Tool
Score a campaign brief
Paste a campaign brief and get the AdCP get_products request and the AAMP CampaignBrief it produces, every value labelled stated, derived, assumed or missing, against 30 typed AdCP filter fields and the AAMP required set.
Rule-based and deterministic: same words in, same payloads out. Nothing is sent anywhere, no account, no email. Paste the brief, read the two scores, then work down the list of what a seller will guess or drop.
Paste the brief
Pre-filled with a worked example. The results below are its output. Replace it with yours and score it. Scoring again clears any accepted assumptions.
The four labels
- stated
- You said it. The exact words are quoted back with the value.
- derived
-
Unambiguously implied, and the rule that fired is printed next to it.
United States
tocountries: ["US"]is a derivation. A channel split is not. - assumed
- The engine picked it. Off by default and listed on its own; it reaches neither payload until you tick its box.
- missing
- Not present and not derivable. The seller will guess it or drop it.
A value can be read correctly, labelled stated, and still reach neither payload,
because neither protocol has a field to carry it.
Scored. Transactable 5 of 10. Expressive 4 of 30. 56 things a seller will guess or drop, 5 of them blocking.
The score
Transactable gate
5 of 10
AAMP CampaignBrief's eight required fields, plus a budget_pct on every channel allocation, plus one check that the AdCP get_products request validates. Counted against the emitted payloads, not your sentences.
5 fail:
- Advertiser identifier (CampaignBrief.advertiser_id) — The AAMP brief will not construct, so nothing downstream of the buyer agent runs.
- Campaign name (CampaignBrief.campaign_name) — The AAMP brief will not construct, and on the AdCP side the campaign has no human-readable handle in any artefact the seller sees.
- Campaign objective (CampaignBrief.objective) — The AAMP brief will not construct, and no downstream allocation logic knows whether to optimise for reach or for conversion.
- Budget currency (CampaignBrief.currency) — AAMP rejects the brief, and AdCP rejects `budget_range` entirely — `currency` is its only required key.
- Budget split by channel (CampaignBrief.channels[].budget_pct) — The AAMP brief will not construct: `budget_pct` is required on every channel allocation, must be `0 < pct <= 100`, and the values must sum to 100.
Expressive coverage, not a target
4 of 30
AdCP filters.* fields your brief populates. The other 26 go to the seller empty, so nothing in them is filtered on. Every populated filter is a hard constraint that deletes products: brief vs filters has the routing rule.
Populated: channels countries end_date start_date
AdCP schema 3.1.13 · buying mode brief · relative dates resolved against 2026-08-13
Relative dates use today's date. Write absolute dates for a result that holds next week.
Every field, and where it came from
4 stated, 5 derived, 0 assumed, 55 missing, of 64 the two protocols can express between them.
| Field | What it is | Value | Label | Evidence |
|---|---|---|---|---|
| Identity | ||||
advertiser_id |
Advertiser identifier | no value | missing | The AAMP brief will not construct, so nothing downstream of the buyer agent runs.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
brand_domain |
Brand domain | no value | missing | The seller cannot resolve brand identity at execution time, so category exclusivity and competitive separation cannot be applied to your buy.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
brand_industries |
Advertiser industry | no value | missing | Publishers holding category-exclusive inventory cannot tell whether your buy conflicts with a competitor already on the property.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
agency_id |
Agency identifier | no value | missing | Billing and seat attribution fall to whatever the buying platform infers.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
campaign_name |
Campaign name | no value | missing | The AAMP brief will not construct, and on the AdCP side the campaign has no human-readable handle in any artefact the seller sees.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
buying_mode |
Buying mode | brief |
derived | buying_mode: 'brief' comes from AnalyzeOptions.buyingMode, not from the brief. It is the only unconditionally required property of get-products-request.json and it describes the call, not the campaign.Request-shaping field: no span, because no words in the brief produced it. |
brief_prose |
Campaign description (residual prose) | Q4 holiday campaign for a CPG snack brand. Channels: CTV plus digital display and online video. Budget: $500,000 net. Market: United States… |
stated | Q4 holiday campaign for a CPG snack brand. Channels: CTV plus digital display and online …The whole input. AdCP `brief` and AAMP `description` carry it verbatim so the prose that mapped to no structured field is not lost; `residual` reports which ranges those are. |
internal_notes |
Internal notes | no value | missing | Internal caveats stay in email instead of travelling with the brief.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
objective |
Campaign objective | no value | missing | The AAMP brief will not construct, and no downstream allocation logic knows whether to optimise for reach or for conversion.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
| Timing | ||||
start_date |
Flight start date | 2026-11-01 |
derived | 'November 1' carries no year; the year 2026 stated at the close of the range was applied to its opening date.…: adults 25-54. Flight: November 1 - December 31, 2026. Go… |
end_date |
Flight end date | 2026-12-31 |
stated | …4. Flight: November 1 - December 31, 2026. Goal: drive incrementa… |
| Budget | ||||
budget_total |
Total budget | 500000 |
stated | …d online video. Budget: $500,000 net. Market: United Sta…One figure, no bound stated. Recorded as the total budget; whether it is a ceiling, a target or a floor is not in the input. |
budget_min |
Minimum budget threshold | no value | missing | Sellers may return low-minimum products that cannot absorb your spend, so the plan fragments across too many line items. |
currency |
Budget currency | no value | missing | AAMP rejects the brief, and AdCP rejects `budget_range` entirely — `currency` is its only required key.The amount carries '$', which names more than one currency. The engine will not pick one; accept the `currency` assumption or write the ISO 4217 code. |
pricing_currencies |
Transactable currencies | no value | missing | Sellers may return products priced only in currencies you cannot settle in, and mandatory signal charges may turn out to be unsatisfiable at buy time. |
is_fixed_price |
Fixed price or auction | no value | missing | Fixed-rate and auction products come back mixed, and the returned `pricing_options` are not pruned to the kind you intended to buy. |
deal_max_cpm |
Maximum CPM | no value | missing | Nothing in the discovery request stops the seller proposing inventory above your price ceiling; you find out at quote time.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
deal_min_impressions |
Minimum impressions per deal | no value | missing | Deals too small to be worth trafficking get proposed and then rejected by hand.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
deal_types |
Preferred deal types | no value | missing | The seller proposes whatever deal mechanics suit it — PG, PD or PA — and the buyer negotiates backwards from there.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
pacing_model |
Pacing model | no value | missing | AAMP silently applies EVEN pacing, so a launch-weighted campaign delivers flat unless someone notices.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
| Geography | ||||
countries |
Countries | ["US"] |
derived | 'United States' → countries: ['US'] (ISO 3166-1 alpha-2 name match).…: $500,000 net. Market: United States. Target demo: adults 25… |
regions |
Regions, states or provinces | no value | missing | Region-bound inventory (regional OOH, local TV) cannot be matched, so the seller offers national products you then have to re-cut. |
metros |
Metros and DMAs | no value | missing | DMA-level inventory cannot be filtered, so you get national products that will not clear a local plan. |
postal_areas |
Postal areas | no value | missing | Postcode-level inventory (direct mail, DOOH, local activation) is invisible to the request. |
geo_proximity |
Proximity to locations | no value | missing | Store-radius and drive-time buys cannot be expressed, so proximity inventory is neither found nor priced.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
required_geo_targeting |
Required geo-targeting capability | no value | missing | Digital products from sellers that cannot target at your granularity stay in the result set and fail at setup.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
| Inventory | ||||
channels |
Channels | [{"adcp":"ctv","aamp":"CTV","surface":"CTV"},{"adcp":"display","aamp":"DISPLAY","surface":"digital display"},{"adcp":"olv","aamp":null,"sur… |
derived | Channel names were matched against AdCP enums/channels.json and AAMP ChannelType. "online video" -> 'online video' is the expansion of the AdCP channel value `olv` ('Online video advertising outside CTV').… snack brand. Channels: CTV plus digital display an……and. Channels: CTV plus digital display and online video. Budge……lus digital display and online video. Budget: $500,000 net. … |
channel_budget_split |
Budget split by channel | no value | missing | The AAMP brief will not construct: `budget_pct` is required on every channel allocation, must be `0 < pct <= 100`, and the values must sum to 100.Channels were named but no split was stated. AAMP will not construct the brief without one; the engine leaves it missing rather than distributing the budget. |
delivery_type |
Guaranteed or non-guaranteed | no value | missing | Guaranteed and non-guaranteed products come back together and the buyer sorts out which is which. |
preferred_delivery_types |
Preferred delivery types | no value | missing | The seller cannot tell a preference from a hard constraint, so it either over-filters or ignores your leaning entirely.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
exclusivity |
Exclusivity | no value | missing | Sole-sponsorship and category-exclusive products are not distinguished from ordinary inventory, so an exclusivity ask never reaches the seller as a filter.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
video_placement_types |
Video placement types | no value | missing | Instream budget can be spent on accompanying-content or standalone inventory without the request ever saying otherwise.No video placement type stated. Instream budget can be spent on accompanying-content or standalone inventory without the request saying otherwise. |
audio_distribution_types |
Audio distribution types | no value | missing | Podcast, broadcast and music-streaming inventory are treated as one pool, so a podcast-only buy can deliver on FM simulcast.No audio distribution type stated. Podcast, broadcast and music-streaming inventory are treated as one pool. |
sponsored_placement_types |
Sponsored placement types | no value | missing | Retail-media requests cannot distinguish sponsored search from sponsored display, and the seller picks for you.No sponsored placement type stated. Retail-media requests cannot distinguish sponsored search from sponsored display. |
social_placement_surfaces |
Social placement surfaces | no value | missing | Feed, stories and short-video surfaces are indistinguishable in the request, so delivery lands wherever the seller has supply.No social placement surface stated. Feed, stories and short-video surfaces are indistinguishable in the request. |
keywords |
Target keywords | no value | missing | Search and retail-media products cannot be matched to your terms, so keyword availability is never assessed.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
property_list |
Approved property list | no value | missing | Discovery is not restricted to your approved inventory, so products on unvetted properties come back as candidates.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
preferred_sellers |
Preferred sellers | no value | missing | Buying-platform routing ignores your preferred supply partners and treats all sellers alike.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
excluded_sellers |
Excluded sellers | no value | missing | Sellers you have blocked are still called and their inventory still returned.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
| Creative | ||||
format_ids |
Ad formats | no value | missing | Sellers return products whose creative specs you cannot fill, and the mismatch is discovered when creative is due.No creative format stated. Sellers return products whose creative specs you may not be able to fill. |
standard_formats_only |
IAB standard formats only | no value | missing | Bespoke and publisher-custom units stay in the result set even when you can only ship IAB standard sizes.Not stated. Bespoke and publisher-custom units stay in the result set even if you can only ship IAB standard sizes. |
creative_ids |
Existing creative assets | no value | missing | The plan is built without knowing which creative exists, so products get chosen for formats nobody has assets for.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
| Audience | ||||
audience_primary |
Primary audience | {"descriptors":[{"kind":"age_range","surface":"adults 25-54","ageMin":25,"ageMax":54}],"adcpSignalTargeting":null,"aampAudiencePlan":{"prim… |
stated | …ed States. Target demo: adults 25-54. Flight: November 1 - D…Recorded as a demographic. `filters.signal_targeting` and `AudiencePlan.primary` both need a resolved reference, which a demo string is not; the descriptors travel as prose (AdCP `brief`, AAMP `AudiencePlan.rationale`) or not at all. |
audience_constraints |
Audience constraints (narrowing) | no value | missing | Precision constraints are dropped and the campaign reaches the primary audience unnarrowed.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
audience_extensions |
Audience extensions (reach) | no value | missing | Reach-extension audiences are silently dropped and the plan under-delivers against its reach goal.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
audience_exclusions |
Audience exclusions (suppression) | no value | missing | Suppression audiences (existing customers, recent converters) are not excluded, and budget is spent re-reaching people you already have.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
audience_strictness |
Audience degradation policy | no value | missing | The buyer agent falls back to its default degradation policy, so a seller that cannot honour part of your plan may have it dropped without anyone being asked.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
| Measurement | ||||
kpi_targets |
KPI targets | no value | missing | Nobody can tell whether the campaign succeeded, and the seller optimises to whichever metric it prefers.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
min_exposures |
Minimum exposures for measurement | no value | missing | Products too small to reach measurement validity stay in the result set and the study is under-powered.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
required_metrics |
Required reporting metrics | no value | missing | Products that cannot report the metric your KPI is measured in are returned, and the gap shows up as `missing_metrics` on delivery reports.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
required_performance_standards |
Required performance standards | no value | missing | Viewability, IVT and attention thresholds are never stated up front, so they become a post-campaign argument instead of a discovery filter.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
required_vendor_metrics |
Required vendor metrics | no value | missing | Products that cannot report your measurement vendor's metrics are returned, and the vendor discovers the gap in flight.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
required_features |
Required protocol features | no value | missing | Sellers that cannot support inline creative management, property-list filtering, catalog management or committed metrics are still returned, and the buy fails at execution.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
trusted_match |
Trusted Match capability | no value | missing | Products without the identity or context match capability you rely on are returned as if they were interchangeable with ones that have it.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
required_axe_integrations |
Required agentic exchange integrations (deprecated) | no value | missing | Nothing at 3.1.13 — the field is deprecated in favour of `trusted_match`, and populating it is a compatibility choice rather than a requirement.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
filters_ext |
Vendor-specific filter extensions | no value | missing | Seller-specific criteria with no standard field have nowhere to go and end up as prose the seller may never parse.No extractor in this engine is competent for this field, so it was not looked for. A field nobody looked for and a field that was looked for and not found are different facts; this is the first kind. |
| Brand safety | ||||
excluded_content_categories |
Excluded content categories | no value | missing | Your ads run beside content you told someone you would avoid, and the first evidence is a screenshot.Brand safety was requested but no categories were named, so nothing is emitted; AAMP `brand_safety.excluded_categories` defaults to [] and AdCP `get_products` has no brand-safety field at all. |
excluded_keywords |
Excluded keywords | no value | missing | Keyword-level blocks are not applied and unsuitable adjacency is caught after delivery, if at all.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
excluded_domains |
Excluded domains and brands | no value | missing | Blocked domains and brands remain eligible, and the block list has to be re-applied in the DSP — if there is one in the path.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
frequency_cap |
Frequency cap | {"max_impressions":3,"period_hours":168} |
derived | 'per week' -> period_hours: 168 (7 days x 24 hours); max_impressions is the stated count 3… brand safety controls, frequency cap 3 per week.…AdCP `get_products` has no frequency field — `enums/frequency-cap-scope.json` applies to a media buy's packages — so a frequency requirement cannot influence which products are returned. |
| Governance | ||||
approval_plan_review |
Human approval: plan review | no value | missing | AAMP's default applies and the pipeline halts at an approval gate the brief never discussed.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
approval_booking |
Human approval: booking | no value | missing | AAMP's default applies and the agent will not book without a human, whatever the brief implied about autonomy.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
approval_creative |
Human approval: creative assignment | no value | missing | AAMP's default applies and creative is assigned to placements with nobody signing it off.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
approval_pacing_adjustment |
Human approval: pacing and reallocation | no value | missing | AAMP's default applies and the agent reallocates budget between channels without asking.The policy-controls extractor is competent for this field, looked for it and found nothing in this brief. |
Assumptions — none applied
Values the engine could pick and has not. Accept one and both payloads are emitted again with it in, labelled assumed. Accept nothing and nothing here reaches a seller. Scoring a brief again clears every acceptance.
'$' is the sign for the US dollar and also for the Canadian, Australian, New Zealand, Singapore, Hong Kong and Mexican dollars, among others. A bare '$' therefore does not name a currency, and the engine did not pick one: `currency` is missing and USD is offered as an assumption you can accept. Write the ISO 4217 code to state it.
Not accepted, so it is in nothing below.
What a seller will guess or drop
56 in all: 5 stop the brief constructing, 1 are read here and travel in neither payload, 50 leave a field empty for the seller to fill however it likes.
Blocks — nothing ships
- blocks Advertiser identifier — Advertiser identifier is one of AAMP CampaignBrief's required values and no value reached the payload. The AAMP brief will not construct, so nothing downstream of the buyer agent runs.
- blocks Campaign name — Campaign name is one of AAMP CampaignBrief's required values and no value reached the payload. The AAMP brief will not construct, and on the AdCP side the campaign has no human-readable handle in any artefact the seller sees.
- blocks Campaign objective — Campaign objective is one of AAMP CampaignBrief's required values and no value reached the payload. The AAMP brief will not construct, and no downstream allocation logic knows whether to optimise for reach or for conversion.
- blocks Budget currency — Budget currency is one of AAMP CampaignBrief's required values and no value reached the payload. AAMP rejects the brief, and AdCP rejects `budget_range` entirely — `currency` is its only required key.
- blocks Budget split by channel — Budget split by channel is one of AAMP CampaignBrief's required values and no value reached the payload. The AAMP brief will not construct: `budget_pct` is required on every channel allocation, must be `0 < pct <= 100`, and the values must sum to 100.
Drops — read here, carried in neither payload
- drops Primary audience — Primary audience is stated in this brief and reaches neither payload. Documented as one of AAMP's nine required fields; in code `target_audience` is `AudiencePlan | None = Field(default=None)`, so the model constructs without it — required by docs, optional by code. On the AdCP side the value is a SignalRef, not a taxonomy ID, and it must be buyer-selectable on the product: `included_signals` and bundled provider signals explicitly do not satisfy `signal_targeting`. AAMP validates contextual refs against IAB Content Taxonomy 3.x and rejects pre-3.x IDs. The buy runs untargeted: AdCP returns run-of-network products, and AAMP treats a null plan as "no audience targeting".
Degrades — 50 fields the seller fills for you
- degrades Brand domain — Brand domain is not stated and not derivable from this brief. The seller cannot resolve brand identity at execution time, so category exclusivity and competitive separation cannot be applied to your buy.
- degrades Advertiser industry — Advertiser industry is not stated and not derivable from this brief. Publishers holding category-exclusive inventory cannot tell whether your buy conflicts with a competitor already on the property.
- degrades Agency identifier — Agency identifier is not stated and not derivable from this brief. Billing and seat attribution fall to whatever the buying platform infers.
- degrades Internal notes — Internal notes is not stated and not derivable from this brief. Internal caveats stay in email instead of travelling with the brief.
- degrades Minimum budget threshold — Minimum budget threshold is not stated and not derivable from this brief. Sellers may return low-minimum products that cannot absorb your spend, so the plan fragments across too many line items.
- degrades Budget currency — The engine could set Budget currency to "USD" — '$' is the sign for the US dollar and also for the Canadian, Australian, New Zealand, Singapore, Hong Kong and Mexican dollars, among others. A bare '$' therefore does not name a currency, and the engine did not pick one: `currency` is missing and USD is offered as an assumption you can accept. Write the ISO 4217 code to state it. — and has not, because nobody accepted it. Accept the key to include it. AAMP rejects the brief, and AdCP rejects `budget_range` entirely — `currency` is its only required key.
- degrades Transactable currencies — Transactable currencies is not stated and not derivable from this brief. Sellers may return products priced only in currencies you cannot settle in, and mandatory signal charges may turn out to be unsatisfiable at buy time.
- degrades Fixed price or auction — Fixed price or auction is not stated and not derivable from this brief. Fixed-rate and auction products come back mixed, and the returned `pricing_options` are not pruned to the kind you intended to buy.
- degrades Maximum CPM — Maximum CPM is not stated and not derivable from this brief. Nothing in the discovery request stops the seller proposing inventory above your price ceiling; you find out at quote time.
- degrades Minimum impressions per deal — Minimum impressions per deal is not stated and not derivable from this brief. Deals too small to be worth trafficking get proposed and then rejected by hand.
- degrades Preferred deal types — Preferred deal types is not stated and not derivable from this brief. The seller proposes whatever deal mechanics suit it — PG, PD or PA — and the buyer negotiates backwards from there.
- degrades Pacing model — Pacing model is not stated and not derivable from this brief. AAMP silently applies EVEN pacing, so a launch-weighted campaign delivers flat unless someone notices.
- degrades Regions, states or provinces — Regions, states or provinces is not stated and not derivable from this brief. Region-bound inventory (regional OOH, local TV) cannot be matched, so the seller offers national products you then have to re-cut.
- degrades Metros and DMAs — Metros and DMAs is not stated and not derivable from this brief. DMA-level inventory cannot be filtered, so you get national products that will not clear a local plan.
- degrades Postal areas — Postal areas is not stated and not derivable from this brief. Postcode-level inventory (direct mail, DOOH, local activation) is invisible to the request.
- degrades Proximity to locations — Proximity to locations is not stated and not derivable from this brief. Store-radius and drive-time buys cannot be expressed, so proximity inventory is neither found nor priced.
- degrades Required geo-targeting capability — Required geo-targeting capability is not stated and not derivable from this brief. Digital products from sellers that cannot target at your granularity stay in the result set and fail at setup.
- degrades Ad formats — Ad formats is not stated and not derivable from this brief. Sellers return products whose creative specs you cannot fill, and the mismatch is discovered when creative is due.
- degrades IAB standard formats only — IAB standard formats only is not stated and not derivable from this brief. Bespoke and publisher-custom units stay in the result set even when you can only ship IAB standard sizes.
- degrades Existing creative assets — Existing creative assets is not stated and not derivable from this brief. The plan is built without knowing which creative exists, so products get chosen for formats nobody has assets for.
- degrades Guaranteed or non-guaranteed — Guaranteed or non-guaranteed is not stated and not derivable from this brief. Guaranteed and non-guaranteed products come back together and the buyer sorts out which is which.
- degrades Preferred delivery types — Preferred delivery types is not stated and not derivable from this brief. The seller cannot tell a preference from a hard constraint, so it either over-filters or ignores your leaning entirely.
- degrades Exclusivity — Exclusivity is not stated and not derivable from this brief. Sole-sponsorship and category-exclusive products are not distinguished from ordinary inventory, so an exclusivity ask never reaches the seller as a filter.
- degrades Video placement types — Video placement types is not stated and not derivable from this brief. Instream budget can be spent on accompanying-content or standalone inventory without the request ever saying otherwise.
- degrades Audio distribution types — Audio distribution types is not stated and not derivable from this brief. Podcast, broadcast and music-streaming inventory are treated as one pool, so a podcast-only buy can deliver on FM simulcast.
- degrades Sponsored placement types — Sponsored placement types is not stated and not derivable from this brief. Retail-media requests cannot distinguish sponsored search from sponsored display, and the seller picks for you.
- degrades Social placement surfaces — Social placement surfaces is not stated and not derivable from this brief. Feed, stories and short-video surfaces are indistinguishable in the request, so delivery lands wherever the seller has supply.
- degrades Target keywords — Target keywords is not stated and not derivable from this brief. Search and retail-media products cannot be matched to your terms, so keyword availability is never assessed.
- degrades Approved property list — Approved property list is not stated and not derivable from this brief. Discovery is not restricted to your approved inventory, so products on unvetted properties come back as candidates.
- degrades Preferred sellers — Preferred sellers is not stated and not derivable from this brief. Buying-platform routing ignores your preferred supply partners and treats all sellers alike.
- degrades Excluded sellers — Excluded sellers is not stated and not derivable from this brief. Sellers you have blocked are still called and their inventory still returned.
- degrades Audience constraints (narrowing) — Audience constraints (narrowing) is not stated and not derivable from this brief. Precision constraints are dropped and the campaign reaches the primary audience unnarrowed.
- degrades Audience extensions (reach) — Audience extensions (reach) is not stated and not derivable from this brief. Reach-extension audiences are silently dropped and the plan under-delivers against its reach goal.
- degrades Audience exclusions (suppression) — Audience exclusions (suppression) is not stated and not derivable from this brief. Suppression audiences (existing customers, recent converters) are not excluded, and budget is spent re-reaching people you already have.
- degrades Audience degradation policy — Audience degradation policy is not stated and not derivable from this brief. The buyer agent falls back to its default degradation policy, so a seller that cannot honour part of your plan may have it dropped without anyone being asked.
- degrades KPI targets — KPI targets is not stated and not derivable from this brief. Nobody can tell whether the campaign succeeded, and the seller optimises to whichever metric it prefers.
- degrades Minimum exposures for measurement — Minimum exposures for measurement is not stated and not derivable from this brief. Products too small to reach measurement validity stay in the result set and the study is under-powered.
- degrades Required reporting metrics — Required reporting metrics is not stated and not derivable from this brief. Products that cannot report the metric your KPI is measured in are returned, and the gap shows up as `missing_metrics` on delivery reports.
- degrades Required performance standards — Required performance standards is not stated and not derivable from this brief. Viewability, IVT and attention thresholds are never stated up front, so they become a post-campaign argument instead of a discovery filter.
- degrades Required vendor metrics — Required vendor metrics is not stated and not derivable from this brief. Products that cannot report your measurement vendor's metrics are returned, and the vendor discovers the gap in flight.
- degrades Required protocol features — Required protocol features is not stated and not derivable from this brief. Sellers that cannot support inline creative management, property-list filtering, catalog management or committed metrics are still returned, and the buy fails at execution.
- degrades Trusted Match capability — Trusted Match capability is not stated and not derivable from this brief. Products without the identity or context match capability you rely on are returned as if they were interchangeable with ones that have it.
- degrades Vendor-specific filter extensions — Vendor-specific filter extensions is not stated and not derivable from this brief. Seller-specific criteria with no standard field have nowhere to go and end up as prose the seller may never parse.
- degrades Excluded content categories — Excluded content categories is not stated and not derivable from this brief. Your ads run beside content you told someone you would avoid, and the first evidence is a screenshot.
- degrades Excluded keywords — Excluded keywords is not stated and not derivable from this brief. Keyword-level blocks are not applied and unsuitable adjacency is caught after delivery, if at all.
- degrades Excluded domains and brands — Excluded domains and brands is not stated and not derivable from this brief. Blocked domains and brands remain eligible, and the block list has to be re-applied in the DSP — if there is one in the path.
- degrades Human approval: plan review — Human approval: plan review is not stated and not derivable from this brief. AAMP's default applies and the pipeline halts at an approval gate the brief never discussed.
- degrades Human approval: booking — Human approval: booking is not stated and not derivable from this brief. AAMP's default applies and the agent will not book without a human, whatever the brief implied about autonomy.
- degrades Human approval: creative assignment — Human approval: creative assignment is not stated and not derivable from this brief. AAMP's default applies and creative is assigned to placements with nobody signing it off.
- degrades Human approval: pacing and reallocation — Human approval: pacing and reallocation is not stated and not derivable from this brief. AAMP's default applies and the agent reallocates budget between channels without asking.
What gets sent
AdCP get_products request
Structured filters plus the residual prose, which AdCP carries as one unvalidated string.
{
"buying_mode": "brief",
"brief": "Q4 holiday campaign for a CPG snack brand. Channels: CTV plus digital display and online video. Budget: $500,000 net. Market: United States. Target demo: adults 25-54. Flight: November 1 - December 31, 2026. Goal: drive incremental household penetration and retail sales lift. Requirements: premium CTV inventory, brand safety controls, frequency cap 3 per week.",
"filters": {
"start_date": "2026-11-01",
"end_date": "2026-12-31",
"countries": [
"US"
],
"channels": [
"ctv",
"display",
"olv"
]
}
}
34 fields left out of this payload, and what that costs
budget_totalstated filters.budget_range requires an ISO 4217 currency and this brief states none; the engine will not assume USD.budget_minmissing Sellers may return low-minimum products that cannot absorb your spend, so the plan fragments across too many line items.currencymissing AAMP rejects the brief, and AdCP rejects `budget_range` entirely — `currency` is its only required key.audience_primarystated AdCP filters.signal_targeting takes SignalRefs resolved against a signals agent. A demographic phrase is not a SignalRef, and this engine makes no network call to turn one into one.audience_exclusionsmissing Suppression audiences (existing customers, recent converters) are not excluded, and budget is spent re-reaching people you already have.brand_domainmissing The seller cannot resolve brand identity at execution time, so category exclusivity and competitive separation cannot be applied to your buy.brand_industriesmissing Publishers holding category-exclusive inventory cannot tell whether your buy conflicts with a competitor already on the property.pricing_currenciesmissing Sellers may return products priced only in currencies you cannot settle in, and mandatory signal charges may turn out to be unsatisfiable at buy time.is_fixed_pricemissing Fixed-rate and auction products come back mixed, and the returned `pricing_options` are not pruned to the kind you intended to buy.regionsmissing Region-bound inventory (regional OOH, local TV) cannot be matched, so the seller offers national products you then have to re-cut.metrosmissing DMA-level inventory cannot be filtered, so you get national products that will not clear a local plan.postal_areasmissing Postcode-level inventory (direct mail, DOOH, local activation) is invisible to the request.geo_proximitymissing Store-radius and drive-time buys cannot be expressed, so proximity inventory is neither found nor priced.required_geo_targetingmissing Digital products from sellers that cannot target at your granularity stay in the result set and fail at setup.format_idsmissing Sellers return products whose creative specs you cannot fill, and the mismatch is discovered when creative is due.standard_formats_onlymissing Bespoke and publisher-custom units stay in the result set even when you can only ship IAB standard sizes.delivery_typemissing Guaranteed and non-guaranteed products come back together and the buyer sorts out which is which.preferred_delivery_typesmissing The seller cannot tell a preference from a hard constraint, so it either over-filters or ignores your leaning entirely.exclusivitymissing Sole-sponsorship and category-exclusive products are not distinguished from ordinary inventory, so an exclusivity ask never reaches the seller as a filter.video_placement_typesmissing Instream budget can be spent on accompanying-content or standalone inventory without the request ever saying otherwise.audio_distribution_typesmissing Podcast, broadcast and music-streaming inventory are treated as one pool, so a podcast-only buy can deliver on FM simulcast.sponsored_placement_typesmissing Retail-media requests cannot distinguish sponsored search from sponsored display, and the seller picks for you.social_placement_surfacesmissing Feed, stories and short-video surfaces are indistinguishable in the request, so delivery lands wherever the seller has supply.keywordsmissing Search and retail-media products cannot be matched to your terms, so keyword availability is never assessed.property_listmissing Discovery is not restricted to your approved inventory, so products on unvetted properties come back as candidates.min_exposuresmissing Products too small to reach measurement validity stay in the result set and the study is under-powered.required_metricsmissing Products that cannot report the metric your KPI is measured in are returned, and the gap shows up as `missing_metrics` on delivery reports.required_performance_standardsmissing Viewability, IVT and attention thresholds are never stated up front, so they become a post-campaign argument instead of a discovery filter.required_vendor_metricsmissing Products that cannot report your measurement vendor's metrics are returned, and the vendor discovers the gap in flight.required_featuresmissing Sellers that cannot support inline creative management, property-list filtering, catalog management or committed metrics are still returned, and the buy fails at execution.trusted_matchmissing Products without the identity or context match capability you rely on are returned as if they were interchangeable with ones that have it.required_axe_integrationsmissing Nothing at 3.1.13 — the field is deprecated in favour of `trusted_match`, and populating it is a compatibility choice rather than a requirement.filters_extmissing Seller-specific criteria with no standard field have nowhere to go and end up as prose the seller may never parse.frequency_capderived AdCP get_products has no field for frequency cap. AAMP takes `max_impressions` + `period_hours`, both `> 0`. `get_products` has no frequency field: AdCP has `enums/frequency-cap-scope.json`, but it applies to a media buy's packages, so a frequency requirement cannot influence which products are returned.
AAMP CampaignBrief
IAB Tech Lab buyer agent, models/campaign_brief.py — eight required fields, cross-field validators.
{
"description": "Q4 holiday campaign for a CPG snack brand. Channels: CTV plus digital display and online video. Budget: $500,000 net. Market: United States. Target demo: adults 25-54. Flight: November 1 - December 31, 2026. Goal: drive incremental household penetration and retail sales lift. Requirements: premium CTV inventory, brand safety controls, frequency cap 3 per week.",
"channels": [
{
"channel": "CTV"
},
{
"channel": "DISPLAY"
}
],
"target_geo": [
{
"geo_type": "COUNTRY",
"geo_value": "US"
}
],
"flight_start": "2026-11-01",
"flight_end": "2026-12-31",
"total_budget": 500000,
"frequency_cap": {
"max_impressions": 3,
"period_hours": 168
}
}
32 fields left out of this payload, and what that costs
channelsderived online video has no AAMP ChannelType (the enum is CTV, DISPLAY, AUDIO, NATIVE, DOOH, LINEAR_TV), so it is absent from the AAMP brief while present in the AdCP request.channel_budget_splitmissing ChannelAllocation requires budget_pct and the percentages must sum to 100. This brief states no split, so the allocations are emitted without it and the model will refuse to construct. The engine does not invent a split to make the model happy.format_idsmissing Sellers return products whose creative specs you cannot fill, and the mismatch is discovered when creative is due.regionsmissing Region-bound inventory (regional OOH, local TV) cannot be matched, so the seller offers national products you then have to re-cut.metrosmissing DMA-level inventory cannot be filtered, so you get national products that will not clear a local plan.postal_areasmissing Postcode-level inventory (direct mail, DOOH, local activation) is invisible to the request.audience_primarystated AudiencePlan.primary is a required AudienceRef carrying type + identifier + taxonomy + version + source. The brief says "adults 25-54", which resolves to no IAB Audience Taxonomy 1.1 identifier. The plan is omitted rather than half-built, so nothing downstream mistakes a phrase for a segment.audience_constraintsmissing Precision constraints are dropped and the campaign reaches the primary audience unnarrowed.audience_extensionsmissing Reach-extension audiences are silently dropped and the plan under-delivers against its reach goal.audience_exclusionsmissing Suppression audiences (existing customers, recent converters) are not excluded, and budget is spent re-reaching people you already have.advertiser_idmissing The AAMP brief will not construct, so nothing downstream of the buyer agent runs.agency_idmissing Billing and seat attribution fall to whatever the buying platform infers.campaign_namemissing The AAMP brief will not construct, and on the AdCP side the campaign has no human-readable handle in any artefact the seller sees.internal_notesmissing Internal caveats stay in email instead of travelling with the brief.objectivemissing The AAMP brief will not construct, and no downstream allocation logic knows whether to optimise for reach or for conversion.currencymissing AAMP rejects the brief, and AdCP rejects `budget_range` entirely — `currency` is its only required key.deal_max_cpmmissing Nothing in the discovery request stops the seller proposing inventory above your price ceiling; you find out at quote time.deal_min_impressionsmissing Deals too small to be worth trafficking get proposed and then rejected by hand.deal_typesmissing The seller proposes whatever deal mechanics suit it — PG, PD or PA — and the buyer negotiates backwards from there.pacing_modelmissing AAMP silently applies EVEN pacing, so a launch-weighted campaign delivers flat unless someone notices.creative_idsmissing The plan is built without knowing which creative exists, so products get chosen for formats nobody has assets for.preferred_sellersmissing Buying-platform routing ignores your preferred supply partners and treats all sellers alike.excluded_sellersmissing Sellers you have blocked are still called and their inventory still returned.audience_strictnessmissing The buyer agent falls back to its default degradation policy, so a seller that cannot honour part of your plan may have it dropped without anyone being asked.kpi_targetsmissing Nobody can tell whether the campaign succeeded, and the seller optimises to whichever metric it prefers.excluded_content_categoriesmissing Your ads run beside content you told someone you would avoid, and the first evidence is a screenshot.excluded_keywordsmissing Keyword-level blocks are not applied and unsuitable adjacency is caught after delivery, if at all.excluded_domainsmissing Blocked domains and brands remain eligible, and the block list has to be re-applied in the DSP — if there is one in the path.approval_plan_reviewmissing AAMP's default applies and the pipeline halts at an approval gate the brief never discussed.approval_bookingmissing AAMP's default applies and the agent will not book without a human, whatever the brief implied about autonomy.approval_creativemissing AAMP's default applies and creative is assigned to placements with nobody signing it off.approval_pacing_adjustmentmissing AAMP's default applies and the agent reallocates budget between channels without asking.
What it will not do
- The transactable score covers the request-level rules this engine is capable of breaking. Full JSON Schema validation against the AdCP release does not run in your browser, so a payload that clears it here can still fail a seller's validator.
Before you send it
- Clear the blocks first. Those are values a required field wants and does not have, so nothing downstream runs.
- Read the drops. You wrote those, and neither protocol has anywhere to put them — say them to your counterparty in a channel that is not this one.
- Settle the assumptions with the people who have to agree. The pre-flight checklist is the list of questions to put to them.
The field map behind the two scores is published as the completeness rubric, concept by concept.
Frequently asked
- Why does it refuse to fill in the channel split?
- Because a split is a commitment and nothing in your text implies one. Values the engine could pick are listed under Assumptions with the rule that produced them, and they reach neither payload until you accept them.
- Will a higher score get me better inventory?
- Unproven. The score counts which values reach a protocol field. Three sales agents in the public AdCP registry answer an anonymous get_products, and one of them returns the same four products whatever the brief says.
- Which AAMP CampaignBrief does it emit?
- The one in models/campaign_brief.py, with eight required fields and cross-field validators. The IAB Tech Lab buyer-agent repository defines a second, incompatible CampaignBrief in models/flow_state.py and ships no adapter between them.