API Reference · Query
Offer Query
Send intent, context, constraints, and pagination fields to discover offers for AI product or agent experiences.
Runtime projection
This route documents the public HTTP request and response surface. It is not the canonical AgentOffer Protocol: use Protocol v1.0 for normative Query and Offer semantics. Service access and credentials are configured separately in the Developer Portal.
Protocol v1.0 also defines optional alternative_offersalongside an empty main list and empty_reason, with a selection reason for each alternative. Service, SDK and Agent integration is pending; these fields are not a guarantee of the deployed HTTP response. See Query alternatives for the example, compatibility limits and rollout order. Existing requests, including force_offer, are unchanged.
Operations
/v1/offers/queryPlacement IDOptional URL query string modifiers.
offer_idstringOffer Wall placement extension: filter the wall's eligible offers by canonical Offer UUID before sorting and pagination. It never adds an Offer outside the placement's wall. Catalog list queries apply viewer country, location, device, and OS targeting. Only explicit offer_id lookups skip those dimensions; serving availability and explicit age eligibility always apply. The same field is also accepted at the top level of an Offer Wall JSON body as a hosted-service extension outside the canonical v1.0 schema. If both URL and body supply it, their UUIDs must match. Invalid or empty values, conflicting values, and URL use with other placement types return HTTP 400 BAD_REQUEST. Omit it to list the wall with normal country, location, device, and OS targeting. No match returns an empty offers array; catalog walls retain CATALOG_NO_AVAILABLE_OFFERS when empty.
format: uuidHeaders that should be present on this request.
AON-Protocol-VersionstringRequired exact current version selector. Send one value equal to `1.0`; every other value is unsupported.
Content-TypeheaderRequest body format for JSON endpoints.
example: application/jsonX-AON-Placement-IdstringOptional placement id, also supported by MCP HTTP requests. Used only when body placement_id (MCP: params.arguments.placement_id) is omitted; an explicit body value always takes precedence. Empty or whitespace-only values are treated as not provided (omitted: anonymous mode when available). Resolved as an active-placement lookup only — the placement decides which application receives attribution, with no ownership check against an API key. OfferWall placements apply configured selection and sorting; catalog OfferWall lists apply viewer country, location, device, and OS targeting (including IP and User-Agent inference); only explicit offer_id lookups skip those dimensions, while serving availability and explicit age eligibility always apply; AI Assistant and Content Assistant placements associate statistics while preserving normal recommendations and engagement suggestions.
example: plc_homepagex-aon-user-pseudo-idstringOptional hosted-service extension carrying a pseudonymous viewer id. It is not part of the canonical v1.0 Query body, is never forwarded to Providers, and is never echoed in the response.
example: pseudo-viewer-xyzx-aon-consentstringOptional hosted-service extension carrying `personalization=granted|denied;jurisdiction=<code>;age=<value>`. It is outside the canonical v1.0 Query body and is never forwarded to Providers.
example: personalization=granted;jurisdiction=EU;age=verifiedJSON payload fields accepted by this endpoint.
objectBounded calling and session context for the current Query. It is not a raw conversation transcript or long-term profile.
5 nested fieldsobjectCalling platform or agent metadata used for diagnostics and integration context.
3 nested fieldsexample: { "name": "shopping-bot", "channel": "api" }namestringOptional non-empty name of the calling platform or agent.
example: shopping-botversionstringOptional caller-reported platform or agent version used for integration diagnostics.
example: 2.1.0channelstringOptional caller-reported interaction channel.
example: apiobjectBounded session continuity for the current conversation.
2 nested fieldsexample: { "previous_request_id": "019dd200-1234-7890-abcd-ef0123456788" }previous_request_idstringOptional Query response identifier used as the explicit comparison baseline for returned hooks.
example: 019dd200-1234-7890-abcd-ef0123456788format: uuidrecent_topicsstring[]Optional bounded list of up to ten recent topic labels. Topics may boost matching overlap but do not change recall or become a raw transcript.
example: ["Tokyo weekend trip", "boutique hotels"]session_idstringOptional session identifier for support correlation.
example: sess_123maxLength: 256conversation_idstring | numberOptional host conversation identifier.
example: conversation_123objectOptional viewer targeting context: location and a verified minimum age. Only location_ids, country, and verified_age_over are accepted; other profile attributes are rejected.
3 nested fieldsexample: { "location_ids": ["1014221"], "country": "US", "verified_age_over": 21 }location_idsstring[]One to ten unique numeric-string AON Location Registry ids for the viewer's current location, most specific first. A resolvable id takes precedence over country. Populate from device, account, or network signals, never from intent text.
example: ["1014221"]countrystringViewer country as an uppercase ISO 3166-1 alpha-2 code. Used when location_ids is absent or unresolvable.
example: USverified_age_overintegerInteger from 13 through 120 that you have verified the viewer is at least, such as 18 or 21. It is a threshold, not an exact age or date of birth; never infer it. Offers whose min_age is above this value are excluded. When omitted, age is not evaluated and age-restricted Offers are not filtered.
example: 21objectThe user's current intent for this Query, not the complete conversation history.
6 nested fieldsobjectExplicit opt-in Flight search constraints.
2 nested fieldsprofilestringRegistered Query profile identifier.
Allowed valuesflightobjectClosed hard constraints for a typed Flight search.
6 nested fieldsquery_kindstringExplicit reference search or traveler-specific full itinerary quote; no inferred default.
Allowed valuesreference_searchtraveler_quoteobject[]Nonempty itinerary legs in request order.
3 nested fieldsobjectRequested departure airport or city.
2 nested fieldskindstringWhether the requested code denotes an airport or city.
Allowed valuesairportcitycodestringThree-letter uppercase location code; spelling alone does not prove registry membership.
pattern: ^[A-Z]{3}$objectRequested arrival airport or city.
2 nested fieldskindstringWhether the requested code denotes an airport or city.
Allowed valuesairportcitycodestringThree-letter uppercase location code; spelling alone does not prove registry membership.
pattern: ^[A-Z]{3}$departure_datestringActual calendar date at the departure location in YYYY-MM-DD form.
format: datepattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}$object[]Traveler groups, required for a quote and forbidden for a reference search. Typed Flight quotes require matching traveler composition.
4 nested fieldstypestringTraveller type used to state the priced traveller composition.
Allowed valuesadultchildinfantcountintegerPositive number of travellers of this type included in the stated itinerary price.
minimum: 1agesinteger[]Completed years of age on the first local departure date, in traveler order. Supply one age per traveler.
infant_seat_requiredboolean[]Seat requirement for each infant at the same index as ages. Supply one seat flag per infant; forbidden for other traveler types.
cabin_classstringExact cabin required on every returned segment.
Allowed valueseconomypremium_economybusinessfirstmax_connectionsintegerMaximum segment changes within each leg.
minimum: 0nonstop_onlybooleanWhen true, each leg must contain one segment with explicitly empty stops.
object[]Exactly one current text or image input item.
3 nested fieldsexample: { "type": "input_text", "text": "noise cancelling headphones under $200" }typestringContent item kind. Most server integrations start with `input_text`.
example: input_textAllowed valuesinput_textinput_imagetextstringFree-text user intent when the item type is `input_text`.
example: noise cancelling headphones under $200minLength: 1maxLength: 200image_urlstringURI of the current image input for an input_image item.
example: https://example.com/current-product.jpgformat: uriprovenancestringWhether the current intent was directly expressed by the user or inferred from context.
example: user_expressedAllowed valuesuser_expressedinferred_contextconfidencenumberConfidence assigned to an inferred intent. It is required for inferred_context and forbidden for user_expressed intent.
example: 0.8minimum: 0maximum: 1object[]At most three unique references that led to a user-expressed intent. Inferred intent cannot carry origin entries.
2 nested fieldskindstringKind of source reference that led to the current intent.
Allowed valuesoffercategorytopicquery_helperidstringOpaque identifier of the referenced source within its declared kind.
minLength: 1maxLength: 256objectStructured signals for the current turn, such as purchase stage, timeframe, or a budget with an explicit currency.
3 nested fieldsobjectNumeric budget values require an explicit ISO 4217 currency; never infer the currency from language, region, or device.
3 nested fieldsexample: { "max": 200, "currency": "USD" }maxnumberRequired non-negative upper budget bound in the declared budget currency.
example: 200minimum: 0currencystringRequired uppercase three-letter currency code for every numeric budget declaration.
example: USDpattern: ^[A-Z]{3}$minnumberOptional non-negative lower budget bound in the declared budget currency.
example: 100minimum: 0purchase_stagestringOptional current stage in the user's purchase journey.
Allowed valuesexploringcomparingready_to_buytimeframestringOptional timeframe in which the user expects to act.
Allowed valuesnowthis_weekthis_monthlaterobjectAON private extension accepted by the hosted REST Query API and MCP. Contains only limit and offset; it is not part of the canonical AgentOffer v1.0 request or the OfferProvider request.
2 nested fieldslimitintegerMaximum offers to return. Defaults to 3 (20 for Flight queries); values above 20 are clamped to 20. Fewer offers may be returned when fewer qualify.
example: 5minimum: 1maximum: 4294967295offsetintegerOffers to skip; defaults to 0. For pages of 5, send offsets 0, 5, 10. Ordinary recommendations are ranked again for each request, so pages are not a frozen snapshot and can overlap.
example: 0minimum: 0maximum: 4294967295request_idstringOptional client request identifier for log correlation. UUIDv7 is recommended.
example: 019dd200-1234-7890-abcd-ef0123456789format: uuidtimestampstringOptional RFC 3339 timestamp for when the request was created.
example: 2026-04-28T03:30:00Zformat: date-timetest_modebooleanOptional test-execution marker that defaults to false. Deployments may apply stricter credential or environment controls.
example: falseobjectExplicit public taxonomy constraints for the current Query.
4 nested fieldsoffer_types[]string[]Hard filter on final public offer_info.offer_type. Supported values are physical_product, digital_goods, content, online_service, and offline_service. Omission preserves type inference; a non-empty array overrides inference; [] clears this filter and prevents reinference for this request. Values in the array are OR; offer_types and other constraint dimensions are AND. Raw duplicates are invalid.
Allowed valuesphysical_productdigital_goodscontentonline_serviceoffline_servicelisting_source_names[]string[]Protocol constraint on final public listing_source.name. Each raw string has 1–160 Unicode code points and must not be ASCII-whitespace-only; raw duplicates are invalid. Match after trimming U+0009–U+000D/U+0020 and folding ASCII A–Z only; other characters match exactly, without aliases or substrings. Omission preserves inference; a non-empty array overrides inference; [] clears and prevents reinference. Values are OR, dimensions are AND. Unknown valid names remain constraints. Runtime support is unvalidated: confirm server support before sending; do not automatically retry by stripping this field.
category_ids[]string[]AON Taxonomy v1 category ids used as public query constraints. Parent ids match descendant offer categories. Ids are case-sensitive; use lowercase registry ids from /protocol/category-taxonomy.
example: othersexcluded_category_ids[]string[]AON Taxonomy v1 category ids to exclude from the current query. Parent ids exclude descendant offer categories.
example: arts_entertainment.adult_entertainmentforce_offerbooleanRequest a fallback recommendation when normal matching returns no offer.
example: falseobjectOptional controls for the shape of the current Query response.
1 nested fieldthinking_modebooleanDefaults to true. Set false when the client does not want `match_reason` in returned offers.
example: trueCurrent v1.0 response envelope with canonical Query metadata and public Offers. Empty matches still return 200 and include the required `data.request_id`, `data.protocol_version`, `data.language`, and empty `data.offers` array.
codestringNo description provided by the current OpenAPI source.
messagestringNo description provided by the current OpenAPI source.
objectNo description provided by the current OpenAPI source.
7 nested fieldsrequest_idstringRequest identifier echoed from the accepted query. AON injects one when the client omits it.
example: 019dd200-1234-7890-abcd-ef0123456789format: uuidprotocol_versionstringTransport protocol line used to produce the response. This is always `1.0` for the current lane and is distinct from `offers[].version`.
example: 1.0Allowed values1.0languagestringLanguage selected for user-facing response content under the stable-v1.0 language-tag profile. It does not express eligibility or targeting.
example: enformat: bcp47object[]Ranked offers that matched the request. Empty array means no eligible offer.
12 nested fieldsoffer_idstringAON-issued, globally unique inventory identity for the logical Offer. It remains stable across returned instances and is distinct from Partner source and request identifiers.
example: 019fc211-c6cd-7e62-9c4d-699c243e6c96format: uuidoffer_instance_idstringAON-issued identity for this dispatch of the Offer. Propagate it unchanged through click and conversion attribution; a later dispatch of the same offer_id receives a different value. It is a derived value in UUID shape: treat it as an opaque string and do not rely on its UUID version bits or on time ordering.
example: 7f3a9c2e-5b1d-8e4a-9c6f-2d8b1a7e4f03format: uuidversionstringOffer document-model lineage. It identifies the Offer payload model and does not select the transport protocol version.
example: 3.0Allowed values3.0objectUser-facing descriptive, category, commercial, and availability information for the Offer.
15 nested fieldsobjectRegistered Offer profile facts; optional on ordinary and non-real-time Query results, required for typed Flight results. Details do not imply a live lookup.
2 nested fieldsprofilestringRegistered Offer profile; validated independently of real-time query selection.
Allowed valuesflighthotel_rategameobjectClosed facts for the selected registered Offer profile. Flight fields below describe one priced air itinerary.
4 nested fieldstrip_typestringDeclared itinerary topology; semantic validation binds it to the number of legs.
Allowed valuesone_wayround_tripmulti_cityobject[]Non-empty traveller counts grouped by traveller type. Each type may occur at most once under semantic validation. Typed Flight quotes require matching traveler composition.
4 nested fieldstypestringTraveller type used to state the priced traveller composition.
Allowed valuesadultchildinfantcountintegerPositive number of travellers of this type included in the stated itinerary price.
minimum: 1agesinteger[]Completed years of age on the first local departure date, in traveler order. Supply one age per traveler.
infant_seat_requiredboolean[]Seat requirement for each infant at the same index as ages. Supply one seat flag per infant; forbidden for other traveler types.
object[]Ordered itinerary legs. Each leg contains one or more ordered flight segments.
2 nested fieldsobject[]Ordered segments for this leg. Semantic validation requires adjacent arrival and departure continuity.
7 nested fieldsobjectScheduled departure airport and airport-local date-time for this segment.
2 nested fieldsairport_codestringThree-letter uppercase airport code; airport-registry membership is outside this profile.
pattern: ^[A-Z]{3}$local_atstringScheduled local date-time at this airport in YYYY-MM-DDTHH:mm:ss form, without a UTC offset or timezone. Producers normalize a source space separator to T and must not infer missing timezone data.
pattern: ^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])T(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$objectScheduled arrival airport and airport-local date-time for this segment.
2 nested fieldsairport_codestringThree-letter uppercase airport code; airport-registry membership is outside this profile.
pattern: ^[A-Z]{3}$local_atstringScheduled local date-time at this airport in YYYY-MM-DDTHH:mm:ss form, without a UTC offset or timezone. Producers normalize a source space separator to T and must not infer missing timezone data.
pattern: ^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])T(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$duration_minutesintegerPositive source-provided scheduled elapsed duration of this segment in minutes. It is authoritative for duration; producers must not infer a timezone to derive it from local_at values.
minimum: 1objectCarrier marketing this flight under the displayed flight number.
1 nested fieldcodestringTwo-character uppercase marketing carrier code; registry membership is not asserted by this profile.
pattern: ^[A-Z0-9]{2}$flight_numberstringCarrier-local flight number without the marketing-carrier prefix.
pattern: ^[0-9]{1,4}[A-Z]?$cabin_classstringPublic cabin class for this segment.
Allowed valueseconomypremium_economybusinessfirstobject[]Source-reported stops within this segment. Omission means unknown; an empty array explicitly means no stops.
3 nested fieldsnamestringSource-provided nonblank location label, which may identify a city rather than an airport.
minLength: 1pattern: \Sairport_codestringSource-provided uppercase airport code; do not infer it from a location name.
pattern: ^[A-Z]{3}$duration_minutesintegerPositive source-provided stop duration in minutes.
minimum: 1duration_minutesintegerSource-provided total leg duration including connection waiting, at least the sum of segment durations.
minimum: 1price_basisstringPrice nature: a reference amount without traveler composition or a complete itinerary total.
Allowed valuesreferenceitinerary_totaltitlestringShort user-facing name used to identify the Offer in a result or presentation.
example: QuietPro 500 HeadphonesdescriptionstringUser-facing explanation of what the Offer provides. It is Offer content, not an AON ranking explanation.
example: Premium truly wireless noise cancelling earbuds with adaptive sound.objectPrimary AON Taxonomy v1 classification for the Offer.
1 nested fieldidstringCanonical AON Taxonomy v1 identifier for the Offer's primary classification. Resolve ids from /protocol/category-taxonomy.
example: travel_tourism.accommodations.hotels_motels_resorts.hotelsobjectOptional user-visible rating summary supplied with the Offer. It is descriptive content and not an AON endorsement.
3 nested fieldsvaluenumberRating value on the declared five-point scale.
example: 4.6minimum: 0maximum: 5countintegerPositive number of observations represented by the rating when supplied.
example: 128minimum: 1sourcestringOptional name of the source that supplied the rating.
example: Verified customersobject[]Optional non-empty, bounded list of structured user-facing facts, such as duration, plan tier, or included features.
4 nested fieldstypestringStable machine-readable key for the displayed fact.
example: plan_tiervaluestring | number | booleanValue of the displayed fact.
example: prounitstringOptional non-empty unit that qualifies the displayed value.
example: monthdisplay_patternstringOptional presentation template for this fact. Only same-item tokens `${type}`, `${value}`, and `${unit}` are allowed.
example: ${value} per ${unit}objectPublic commercial presentation; required for typed Flight results and optional for Generic results. It excludes internal commission, settlement, and eligibility policy.
4 nested fieldsobjectObserved original-price context. It is only valid together with commercial.price and does not prove display_price or foreign-exchange freshness. May accompany registered profile facts on ordinary requests; profile-required observation and expiry rules apply.
2 nested fieldsobserved_atstringRFC 3339 instant at which the producer observed the original Offer price.
format: date-timevalid_untilstringOptional RFC 3339 instant through which the producer explicitly asserts the observed original price remains valid; semantic validation requires it to be after observed_at.
format: date-timeobjectOriginal price; required for typed Flight results and optional for Generic results. Flight traveler_quote requires an itinerary total including taxes and mandatory fees.
4 nested fieldstax_statusstringOriginal price tax and mandatory-fee status under the returned Offer profile; typed Flight traveler_quote requires included.
Allowed valuesincludedexcludedunknownamountstringCanonical decimal string for the displayed public Offer price, not Goal commission.
example: 189.99currencystringUppercase three-letter currency code for the displayed public Offer price.
example: USDpattern: ^[A-Z]{3}$unitstringOptional unit or billing period to which the displayed price applies. Typed Flight permits only one_time.
example: monthAllowed valuesone_timenightdayweekmonthyearobjectOptional AON-derived presentation amount and currency for this Query response. It overrides only price.amount and price.currency for display and is invalid without an original price.
2 nested fieldsamountstringCanonical non-negative decimal amount to present for this response, with at most twelve integer digits and six fractional digits.
example: 718.42pattern: ^(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,6})?$currencystringUppercase three-letter target presentation currency syntax; registry membership is not asserted.
example: CNYpattern: ^[A-Z]{3}$fulfillment_notestringOptional short user-facing note about fulfillment or a material price condition.
short_descriptionstringOptional concise display summary for the Offer. It is limited to 500 code points and 50 word-like segments.
example: Premium noise cancelling earbuds with adaptive sound.maxLength: 500offer_typestringHigh-level class of what is offered. It supports presentation and product understanding; it is not the executable consumer action.
example: online_serviceAllowed valuesphysical_productdigital_goodscontentonline_serviceoffline_servicesecondary_category_idsstring[]Optional non-empty list of additional AON Taxonomy v1 classifications. Entries add descriptive coverage and must remain distinct from the primary category and one another under semantic validation.
example: ["finance.investing.crypto_and_digital_assets"]min_ageintegerOptional minimum audience age in years that the Partner declared for this Offer, derived by AON from the Offer's targeting rules. Omitted when no minimum is declared, which does not mean the Offer suits all ages. It is not an AON-certified age rating; do not present the Offer to a viewer you know is younger.
example: 18minimum: 1maximum: 120recommendation_reasonstringOptional static Partner- or provider-authored Offer copy. It is not the per-request AON match explanation and is unaffected by thinking_mode.
start_atstringOptional start of the user-visible Offer availability window.
format: date-timeexpire_atstringOptional end of the user-visible Offer availability window. When both bounds are supplied, it must not precede start_at.
format: date-timeobjectPublic identity of the party responsible for the Offer.
6 nested fieldsidstringStable identifier for the merchant, brand, provider, publisher, or other party responsible for the Offer. It is not an Offer identifier.
example: ent_audiomartnamestringUser-facing name of the entity responsible for the Offer.
example: AudioMarttypestringRole of the entity in relation to the Offer.
example: providerAllowed valuesmerchantbrandproviderpublisherotherdescriptionstringOptional non-empty user-facing description of the responsible entity.
example: Consumer electronics retailer.websitestringOptional public HTTPS website for the responsible entity. It is identity metadata, not the action destination, and must not contain URI userinfo.
example: https://www.audiomart.exampleformat: uripattern: ^[Hh][Tt][Tt][Pp][Ss]://logostringOptional public logo for the responsible entity. It is an absolute HTTPS resource URI and must not contain URI userinfo.
example: https://cdn.example.com/logos/audiomart.pngformat: uripattern: ^[Hh][Tt][Tt][Pp][Ss]://objectOptional provenance for the external platform or site where listing information was observed.
4 nested fieldskindstringClassification of the external place where user-facing listing information was observed.
Allowed valuesplatformmarketplacemerchant_siteofficial_siteothernamestringUser-facing name of the observed platform or site. It remains distinct from entity.name.
observed_atstringUTC timestamp for when the listing information was observed, not the Offer availability window.
format: date-timelogostringOptional explicit logo of the observed platform or site. It is an absolute HTTPS resource URI without userinfo and must not be inferred from other Offer fields.
format: uripattern: ^[Hh][Tt][Tt][Pp][Ss]://object[]Optional non-empty list of user-facing creative assets for presenting the Offer. It is distinct from entity.logo and listing_source.logo.
5 nested fieldsurlstringAbsolute HTTPS URI for retrieving the creative asset; URI userinfo is forbidden.
example: https://example.com/assets/quietpro-500-hero.jpgformat: uripattern: ^[Hh][Tt][Tt][Pp][Ss]://formatstringCreative asset format.
example: imageAllowed valuesimagevideohtml5tagstringOptional producer-supplied label for the creative asset. It must not be treated as targeting or eligibility data.
example: herodimensionsstringOptional producer-declared dimensions or aspect descriptor for rendering.
example: 1200x628alt_textstringOptional accessibility text describing the creative asset.
objectExecutable user-choice destination associated with the Offer.
6 nested fieldstypestringTechnical form of the executable action destination.
example: open_urlAllowed valuesopen_urldeep_linkopen_appcustomobjectExecutable action parameters. Stable v1.0 defines one safe absolute URI destination.
1 nested fieldurlstringSafe absolute URI invoked when the user chooses the action. javascript, data, vbscript, and file schemes are forbidden; open_url additionally requires HTTPS.
example: https://partner.example.com/products/quietpro-500format: uripattern: ^(?!(?:[Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt]|[Dd][Aa][Tt][Aa]|[Vv][Bb][Ss][Cc][Rr][Ii][Pp][Tt]|[Ff][Ii][Ll][Ee]):)[A-Za-z][A-Za-z0-9+.-]*:namestringOptional non-empty concise call-to-action label for the user.
example: Shop nowconsumer_actionstringUser-intent classification for the action. It describes what the user is invited to do and is distinct from a conversion Goal event.
example: buyAllowed valueslearn_morebuybooksubscribedownloadclaimsign_upopendescriptionstringOptional non-empty user-facing explanation of what invoking the action does.
example: Open the product page on the merchant site.destination_typesstring[]Optional non-empty declaration of destination surfaces supported by the action. It does not replace action.type or payload.url.
example: webAllowed valueswebappphoneemailobject[]Public conversion event declarations and their associated public pricing model. Goals are returned in the array order provided by the source and that source order is preserved; the order has no business meaning (not primary/secondary, not funnel stage).
3 nested fieldseventstringCanonical conversion event name for this Goal; events are unique within one Offer.
example: conversionpattern: ^[a-z][a-z0-9_]{0,63}$objectGross commission the Partner declares payable to AON for an approved, attributed occurrence of this Goal, before fees, developer share, refunds, holds, disputes, or adjustments.
4 nested fieldsmodelstringGross Partner-to-AON commission model for an approved, attributed occurrence of the Goal. It is not the user-visible Offer price or final settlement.
example: cpaAllowed valuescpacpsamountstringStrictly positive canonical decimal amount of gross Partner-to-AON commission for one approved Goal event.
example: 10pattern: ^(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,6})?$excluded: 0, 0.0, 0.00, 0.000, 0.0000, 0.00000, 0.000000currencystringUppercase three-letter currency code for the CPA commission amount.
example: USDpattern: ^[A-Z]{3}$ratestringStrictly positive canonical percentage rate, greater than zero and no greater than 100, applied to the gross conversion amount in its reported currency.
example: 12.5pattern: ^(?:100(?:\.0{1,4})?|[1-9]?[0-9](?:\.[0-9]{1,4})?)$excluded: 0, 0.0, 0.00, 0.000, 0.0000descriptionstringOptional user-facing explanation of what outcome constitutes the Goal; it does not change attribution or payment terms.
object[]Optional non-empty, bounded list of source-provided statements about the Offer. They are not AON endorsements.
2 nested fieldskindstringClassification of the statement so consumers can present it with appropriate context.
Allowed valuesadvertiser_claimuser_benefitavailabilitytextstringUser-facing statement text. It remains source-provided content, not an AON endorsement.
content_languagestringLanguage tag for user-facing Offer text under the stable-v1.0 BCP-47 syntax profile. It does not express targeting eligibility or select the protocol version.
example: en-USformat: bcp47match_reasonstringAON-authored, per-request user-facing explanation of why this Offer matches the current intent. It is omitted when response_options.thinking_mode is false and must not expose private reasoning or ranking data.
objectOptional non-empty user-facing guidance for refining the current intent or exploring an adjacent topic. It does not change returned Offers.
2 nested fieldsobject[]Up to three non-empty suggestions that narrow or clarify the current Query intent.
3 nested fieldslabelstringShort user-facing label for the refinement.
minLength: 1maxLength: 160objectStructured and bounded instruction for deriving a subsequent Query without deleting current request fields.
2 nested fieldsobjectRequired non-empty partial update limited to intent.signals and category, offer-type, or listing-source constraints. Omission preserves values, objects merge, arrays replace, and null is invalid.
2 nested fieldsobjectOptional intent portion of the next-Query update; when present it contains non-empty signals.
1 nested fieldobjectNon-empty intent signals proposed for the next Query. Omitted signal members remain unchanged.
3 nested fieldsobjectOptional budget update with an explicit upper bound and currency.
3 nested fieldsmaxnumberRequired non-negative replacement upper budget bound.
minimum: 0currencystringRequired uppercase three-letter currency code for the budget update.
pattern: ^[A-Z]{3}$minnumberOptional non-negative replacement lower budget bound.
minimum: 0purchase_stagestringOptional replacement purchase-journey stage.
Allowed valuesexploringcomparingready_to_buytimeframestringOptional replacement action timeframe.
Allowed valuesnowthis_weekthis_monthlaterobjectNon-empty protocol constraint update. Supplied arrays replace prior arrays; omission preserves existing values. For offer_types and listing_source_names, [] clears the filter and prevents reinference in the resulting request. listing_source_names runtime support is unvalidated: confirm server support before adopting that extension.
4 nested fieldscategory_ids[]string[]Replacement list of included AON Taxonomy v1 category ids.
excluded_category_ids[]string[]Replacement list of excluded AON Taxonomy v1 category ids.
offer_types[]string[]Replacement for constraints.offer_types, with the same five supported values, hard-filter behavior, duplicate rejection, and OR/AND semantics as the Query field.
Allowed valuesphysical_productdigital_goodscontentonline_serviceoffline_servicelisting_source_names[]string[]Protocol-only replacement for constraints.listing_source_names, with the same raw string bounds, duplicate rejection, ASCII trim/case matching, and OR/AND semantics as the Query field. Runtime support is unvalidated.
object[]Optional non-empty provenance references to copy into intent.origin if the user adopts this suggestion.
2 nested fieldskindstringKind of source reference for the suggested next Query.
Allowed valuesoffercategorytopicquery_helperidstringOpaque identifier of the suggested Query source within its declared kind.
minLength: 1maxLength: 256speakstringOptional longer phrasing suitable for voice or conversational presentation.
minLength: 1maxLength: 500object[]Up to two adjacent-topic suggestions ordered by descending confidence within this response.
4 nested fieldslabelstringShort user-facing label for the related topic.
minLength: 1maxLength: 160basisstringDeclared relationship between the follow-up topic and the current Query.
Allowed valuescategory_complementsequential_journeyproblem_to_productcomparison_alternativeuser_interestseasonalobjectStructured and bounded instruction for deriving a subsequent Query without deleting current request fields.
2 nested fieldsobjectRequired non-empty partial update limited to intent.signals and category, offer-type, or listing-source constraints. Omission preserves values, objects merge, arrays replace, and null is invalid.
2 nested fieldsobjectOptional intent portion of the next-Query update; when present it contains non-empty signals.
1 nested fieldobjectNon-empty intent signals proposed for the next Query. Omitted signal members remain unchanged.
3 nested fieldsobjectOptional budget update with an explicit upper bound and currency.
3 nested fieldsmaxnumberRequired non-negative replacement upper budget bound.
minimum: 0currencystringRequired uppercase three-letter currency code for the budget update.
pattern: ^[A-Z]{3}$minnumberOptional non-negative replacement lower budget bound.
minimum: 0purchase_stagestringOptional replacement purchase-journey stage.
Allowed valuesexploringcomparingready_to_buytimeframestringOptional replacement action timeframe.
Allowed valuesnowthis_weekthis_monthlaterobjectNon-empty protocol constraint update. Supplied arrays replace prior arrays; omission preserves existing values. For offer_types and listing_source_names, [] clears the filter and prevents reinference in the resulting request. listing_source_names runtime support is unvalidated: confirm server support before adopting that extension.
4 nested fieldscategory_ids[]string[]Replacement list of included AON Taxonomy v1 category ids.
excluded_category_ids[]string[]Replacement list of excluded AON Taxonomy v1 category ids.
offer_types[]string[]Replacement for constraints.offer_types, with the same five supported values, hard-filter behavior, duplicate rejection, and OR/AND semantics as the Query field.
Allowed valuesphysical_productdigital_goodscontentonline_serviceoffline_servicelisting_source_names[]string[]Protocol-only replacement for constraints.listing_source_names, with the same raw string bounds, duplicate rejection, ASCII trim/case matching, and OR/AND semantics as the Query field. Runtime support is unvalidated.
object[]Optional non-empty provenance references to copy into intent.origin if the user adopts this suggestion.
2 nested fieldskindstringKind of source reference for the suggested next Query.
Allowed valuesoffercategorytopicquery_helperidstringOpaque identifier of the suggested Query source within its declared kind.
minLength: 1maxLength: 256confidencenumberProducer-normalized relevance estimate. It is comparable only among follow-up topics in this response, not across requests or producers.
minimum: 0maximum: 1object[]Optional change cues comparing a returned Offer with an explicit previous Query baseline. Hooks do not register watches or guarantee delivery.
6 nested fieldskindstringCategory of changed Offer information observed against the baseline.
Allowed valuesprice_changeavailability_changeeligibility_changecontent_changetitlestringShort user-facing title for the change cue.
minLength: 1maxLength: 160subject_offer_idstringoffer_id of the returned Offer whose current representation is being compared.
format: uuidbaseline_request_idstringPrior Query response id used as the comparison baseline. It must equal the current request context.session.previous_request_id.
format: uuidobjectStructured and bounded instruction for deriving a subsequent Query without deleting current request fields.
2 nested fieldsobjectRequired non-empty partial update limited to intent.signals and category, offer-type, or listing-source constraints. Omission preserves values, objects merge, arrays replace, and null is invalid.
2 nested fieldsobjectOptional intent portion of the next-Query update; when present it contains non-empty signals.
1 nested fieldobjectNon-empty intent signals proposed for the next Query. Omitted signal members remain unchanged.
3 nested fieldsobjectOptional budget update with an explicit upper bound and currency.
3 nested fieldsmaxnumberRequired non-negative replacement upper budget bound.
minimum: 0currencystringRequired uppercase three-letter currency code for the budget update.
pattern: ^[A-Z]{3}$minnumberOptional non-negative replacement lower budget bound.
minimum: 0purchase_stagestringOptional replacement purchase-journey stage.
Allowed valuesexploringcomparingready_to_buytimeframestringOptional replacement action timeframe.
Allowed valuesnowthis_weekthis_monthlaterobjectNon-empty protocol constraint update. Supplied arrays replace prior arrays; omission preserves existing values. For offer_types and listing_source_names, [] clears the filter and prevents reinference in the resulting request. listing_source_names runtime support is unvalidated: confirm server support before adopting that extension.
4 nested fieldscategory_ids[]string[]Replacement list of included AON Taxonomy v1 category ids.
excluded_category_ids[]string[]Replacement list of excluded AON Taxonomy v1 category ids.
offer_types[]string[]Replacement for constraints.offer_types, with the same five supported values, hard-filter behavior, duplicate rejection, and OR/AND semantics as the Query field.
Allowed valuesphysical_productdigital_goodscontentonline_serviceoffline_servicelisting_source_names[]string[]Protocol-only replacement for constraints.listing_source_names, with the same raw string bounds, duplicate rejection, ASCII trim/case matching, and OR/AND semantics as the Query field. Runtime support is unvalidated.
object[]Optional non-empty provenance references to copy into intent.origin if the user adopts this suggestion.
2 nested fieldskindstringKind of source reference for the suggested next Query.
Allowed valuesoffercategorytopicquery_helperidstringOpaque identifier of the suggested Query source within its declared kind.
minLength: 1maxLength: 256descriptionstringOptional user-facing explanation of the observed change.
minLength: 1maxLength: 500empty_reasonstringPrimary explanation required exactly when offers is empty in a Generic Query response. Forbidden in typed Flight responses, including empty results. If several causes apply, canonical precedence selects one value.
Allowed valuesfrequency_cappedbelow_relevance_thresholdscene_suppressedno_materialconsent_missingextraobjectNo description provided by the current OpenAPI source.
AON-Protocol-VersionstringHTTP response header that echoes the exact selected current Query protocol version on successful v1.0 responses.
example: 1.0Allowed values1.0X-AON-TRACE-IDstringHTTP response header for AON support diagnostics. It is not part of the JSON response body.
example: trc_01HX6P8T4K2W9QX6Y7Z8A9BCDEMalformed request body, unsupported field value, or invalid request shape.
- Missing `intent.content[]` or unsupported content item type.
- `constraints.category_ids[]` contains a value outside AON Taxonomy v1.
- `intent.provenance` or another Protocol v1.0 required field is missing.
- Validate the request against the documented field table.
- Start from the minimal request example, then add `constraints.category_ids` only when the user intent maps to a taxonomy id.
Curated guidance, not contract schema
The request did not identify a placement (`UNAUTHORIZED`).
- No placement id was sent and anonymous mode does not apply — for example the request carried an `aon_test_` key outside the Public Test Sandbox.
- `X-AON-Test: true` was sent without a test credential (`ENV_MISMATCH`). No Query request needs this header, including the Public Test Sandbox.
- Send the placement id copied from your application's Placements page in Developer Portal.
- Confirm the request is sent to the matching staging or production base URL.
Curated guidance, not contract schema
The integration exceeded the accepted request rate for the current window.
- A worker retried immediately in a loop.
- Many sessions of the same application retry without backoff.
- Apply exponential backoff with jitter.
- Respect retry windows when returned and avoid duplicate immediate retries.
Curated guidance, not contract schema
Platform envelope error code for a non-empty but malformed, inactive, unauthorized, or unknown placement id. It is returned as the service envelope `code`, not as a canonical AgentOffer Protocol response payload field.
- A non-empty `X-AON-Placement-Id` value is malformed (longer than 64 characters), nonexistent, inactive, or belongs to another app. Empty or whitespace-only values are treated as not provided (anonymous mode when available, otherwise `UNAUTHORIZED`).
- The placement exists, but its application is not currently serving.
- Confirm the placement id was copied from the app's placement configuration.
- Send the placement id in the `X-AON-Placement-Id` header, not under `constraints`.
Curated guidance, not contract schema
Platform envelope error code for a catalog-backed placement whose configured catalog has no available offers. It is returned as the service envelope `code`, not as a canonical AgentOffer Protocol response payload field.
- The placement routes to an offerwall catalog data source.
- The selected catalog currently has no active eligible offers.
- Review the catalog configuration and offer lifecycle state.
- Retry only after inventory changes; immediate retries with the same placement should not change the result.
Curated guidance, not contract schema
Behavior, compatibility, and source notes
Current Offer Query contract for new integrations. Send exactly one `AON-Protocol-Version` header whose field value is exactly `1.0` to select this contract. If the header is omitted, the server falls back to the legacy 0.1 response shape (no `data.protocol_version`) for backward compatibility, so new integrations must always send it. A duplicated header, or an unknown, approximate, range, or otherwise non-exact selector, returns HTTP 400 `UNSUPPORTED_PROTOCOL_VERSION`; no fallback is performed for those. Successful responses echo `1.0` in both the response header and `data.protocol_version`, send `Vary: AON-Protocol-Version`, and return `data.offers[]` following the canonical public Offer v1.0 schema. The caller's identity for this endpoint is resolved from a placement, not an API key: pass body `placement_id`, or the `X-AON-Placement-Id` header (body takes precedence), or (production only, during the compatibility window) rely on a legacy API key that is listed in the server's key-to-placement compatibility map. Empty or whitespace-only placement values are treated as not provided. With no identity at all, the request is served in anonymous mode through the AON default placement (response `extra.identity.mode="anonymous"`, no earnings, no idempotent replay: a retry recomputes) when the deployment configures it; only when anonymous mode is unavailable or off does the request return HTTP 401 `UNAUTHORIZED`. A `Bearer` Authorization header does not supply the placement: a live key without a placement is served in anonymous mode with an `extra.key_notice`, and a non-sandbox `aon_test_` key without a placement returns HTTP 401 `UNAUTHORIZED`. The placement decides which application receives attribution; it is not checked against any API key. OfferWall placements apply configured selection and sorting; catalog OfferWall lists apply viewer country, location, device, and OS targeting (including IP and User-Agent inference); only explicit offer_id lookups skip those dimensions, while serving availability and explicit age eligibility always apply; AI Assistant and Content Assistant placements associate statistics while preserving normal recommendations and engagement suggestions. Non-empty but invalid, unknown, or inactive placement values return `INVALID_PLACEMENT`; an empty catalog placement returns `CATALOG_NO_AVAILABLE_OFFERS`; a placement whose application is deleted or not serving returns HTTP 403 `APPLICATION_NOT_SERVING`; a placement owned by a suspended developer returns HTTP 403 `DEVELOPER_SUSPENDED`. Unknown or inactive `constraints.category_ids` fail closed with HTTP 400 `INVALID_CATEGORY_ID` and an indexed `extra.field_path`; resolve category ids first rather than guessing. If the caller supplies `request_id`, this endpoint replays a cached SUCCESS response for that (caller identity, request id) pair for 10 minutes without duplicating the five write-side effects: inbound journal, impressions/billing projection, outbound metrics, partner journal, and embedding journal. `request_id` should be an unguessable value (UUID). A retryable HTTP 503 `SERVICE_BUSY` may be retried with the same `request_id`; HTTP 409 `QUERY_REPLAY_UNAVAILABLE` means the durable query is finalized but its response body can no longer be replayed, so issue a new logical request with a new `request_id`. Network Offer Wall placements use a model-free eligible list when intent is omitted, or literal lexical matching when text is explicitly supplied; they do not infer hidden constraints or split multiple intents. Catalog walls retain their configured membership and ordering. Ordinary AI/Content Assistant queries retain semantic search and only their existing visibility=all inventory; switching away from a wall does not retain offerwall_only inventory. Network wall pagination uses an absolute offset in the current eligible sequence before shown-history exclusions; follow extra.pagination.next_offset rather than calculating offset + returned. Network total is null and inventory is not snapshotted across requests. A necessary upstream failure is not a successful empty match: generic hosted Query returns 503 UPSTREAM_UNAVAILABLE, or 504 QUERY_TIMEOUT when a necessary call actually timed out. These are deployment-owned errors; specialized Flight/Hotel contracts remain unchanged. There is no new short Query-wide deadline. Only a cached SUCCESS response can be replayed: a finalized failed/cancelled operation without a success cache returns QUERY_REPLAY_UNAVAILABLE on the same logical key.
- This is the main entry point for offer discovery. Identify your integration with your placement id; no other credential is needed.
- Persist `offers[].offer_instance_id` for downstream attribution and conversion reporting.
- Placement identity: send the placement id in the `X-AON-Placement-Id: plc_…` header. Traffic is attributed to the application that owns the placement. A placement id is not a secret, so you can call from a browser or app.
- All placement types accept nested `pagination: { limit, offset }` as an AON private extension under v1.0. The effective limit is 1–20 and defaults to 3 (20 for Flight); values above 20 are clamped. Offset defaults to 0. Ordinary placements still require intent. These fields are not part of the canonical AgentOffer request or the outbound OfferProvider contract.
- Use a new request_id for each page and reuse that id only for retries of the same page. Ordinary recommendation pages can overlap as ranking and inventory change; deduplicate by offer_id. Their responses do not promise a stable total or extra.pagination metadata.
- Offer Wall placements (placement type `offerwall`) also allow omitted intent and historical top-level limit/offset aliases. Their responses add extra.pagination with limit, offset, returned, total, has_more, and next_offset. Fetch next_offset while has_more is true. See /offer-wall/api.
- Flight `reference_search` forbids travelers and returns price_basis reference; `traveler_quote` requires traveler groups and returns price_basis itinerary_total with tax_status included. Hard itinerary constraints must match; intent text does not override them.
- Typed Flight success returns usable Offers without source execution metadata. Empty offers means no usable results for this request; it does not claim market-wide coverage. Total source failure remains an error.
- Ordinary queries, including non-real-time requests, may return registered `offer_info.details` with profile-required price, tax and quote facts. Details alone do not imply a live lookup. Opt in to strict real-time Flight matching with `intent.details.profile: flight` and explicit `data.query_kind` and itinerary legs. Typed Flight results require complete matching Flight details and original price including tax_status. Public responses omit execution metadata; empty typed results mean no usable Offers for this request. Canonical protocol support does not by itself certify a deployed provider capability.
Quick Recipes
Minimal request
Use this shape to validate placement identity and the required intent/context envelope.
- Send
intent.content[]with at least one user input item. - Include
intent.provenanceand send only bounded context for the current conversation. - Use the full request example in Endpoints when you need a copyable payload.
Production request
Add platform, bounded session context, structured signals, and public constraints once the minimal request works.
- Add
context.platformandcontext.sessionfor bounded continuity. - Keep sending your placement id in the
X-AON-Placement-Idheader. - Use
constraints.category_idswhen the user intent maps to AON Taxonomy v1. - Set
response_options.thinking_modeto false when the client does not need match reasons.
Page through recommendations
Send the AON pagination extension with the same intent and constraints for each page.
- Use
pagination: { limit: 5, offset: 0 }, then offsets 5, 10, and so on. The effective limit is at most 20. - Use a new
request_idfor each page; reuse it only when retrying that same page, otherwise idempotent replay can return the previous response. - Ordinary recommendations can change between requests. Deduplicate accumulated results by
offer_id; offset pagination does not guarantee distinct pages or a stable total. - Stop on a short or empty page. Ordinary Query responses do not promise
extra.pagination; Offer Wall responses provide their own paging metadata.
Empty result
Treat an empty `offers` array as a valid response. Show an empty state or relax constraints.
code: SUCCESSwithdata.offers: []is not an integration failure.- Log
data.request_idbefore retrying or relaxing constraints. - Keep the complete empty-result payload in Endpoints as the response reference.
- Do not treat an empty match as HTTP 204; the JSON body is intentional so clients keep request correlation.
Error response
Handle malformed payloads, invalid credentials, placement errors, and rate limits explicitly.
- Use 400 to fix request shape or missing required fields.
INVALID_PLACEMENTandCATALOG_NO_AVAILABLE_OFFERSare platform envelopecodevalues for placement-scoped queries.- Use 401 to check that the request sends a placement id (without one it is served in anonymous mode when available).
- Use 429 backoff with jitter and avoid immediate retry loops.
Common Questions
Can ordinary Query requests choose a result count and page through recommendations?
Yes. Send nested `pagination.limit` and `pagination.offset` to the hosted REST Query API or MCP. These are AON private extensions, not canonical AgentOffer v1.0 fields. The default limit is 3 (20 for Flight), the effective maximum is 20, and offset defaults to 0. Ordinary placements still require intent. Only Offer Wall also accepts the historical top-level limit/offset aliases. Use a new request_id per page and deduplicate by offer_id because ranking and inventory can change between requests.
What is the difference between `intent` and `constraints`?
`intent` describes what the user wants in natural language or multimodal content. `constraints` is for low-ambiguity structured constraints. The first public version only exposes canonical category constraints.
Should `category_ids` use root ids or leaf ids?
Send AON Taxonomy v1 ids from /protocol/category-taxonomy. A root id such as `travel_tourism` matches descendants, a leaf id such as `computers_electronics.computers.software` is more precise, and `others` currently matches only stored id `others`. Historical v0.1 aliases may be tolerated in migration paths, but public integrations should store and send taxonomy ids.
How do we correlate conversions?
Persist the returned `offer_instance_id`. It is the dispatch-level identity for click, conversion, and settlement attribution; do not replace it with a legacy tracking URL.
What should we do when no offers are returned?
Render a normal empty state, log the `request_id`, and consider relaxing constraints before retrying. Do not treat `offers: []` as a failed request.
How should we debug 401 responses?
Check that the request sends your placement id in the `X-AON-Placement-Id` header and does not send `X-AON-Test`. Offer Query never needs an API key; only the Public Test Sandbox uses its shared test key.
How should we handle 429 responses?
Apply exponential backoff with jitter, honor retry windows when present, and avoid immediate retry loops from the same session or worker.
Where should we put the placement id?
Send it in the `X-AON-Placement-Id` header on `POST /v1/offers/query`. Do not nest it inside `constraints`.
Is `/v1/sdk/offers/query` still available?
No — `/v1/sdk/offers/query` was retired in SVC-PLATFORM-F260813162251. All REST integrations, including former SDK-facing callers, now use `POST /v1/offers/query`.
Implementation checklist · 3 items
- Get your placement id from Quick Start or Developer Portal first (or omit it to run in anonymous mode, with no earnings).
- Send a structured `intent` payload, even for simple text-only queries.
- Persist returned tracking URLs or identifiers for downstream attribution.
Related links
Optionally resolve registry ids for location pickers, normalization, or Offer-side geographic targeting; Query v1.0 has no viewer-location input.
Browse the category ids accepted by constraints.category_ids.
Shared HTTP status, body envelope, and retry guidance.