# Offer Query

Source: https://docs.aon.pro/api/offer-query

> Derived from the same AON Docs release as the source page.

API Reference · 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](https://docs.aon.pro/protocol) for normative Query and Offer semantics. Service access and credentials are configured separately in the Developer Portal.

Protocol v1.0 also defines optional `alternative_offers`alongside 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](https://docs.aon.pro/protocol#query-alternatives) for the example, compatibility limits and rollout order. Existing requests, including `force_offer`, are unchanged.

## Operations

**POST** `/v1/offers/query`

Search offers by intent

Authentication: Bearer required. Source: OpenAPI security.

### Request

Headers

Headers that should be present on this request.

#### `AON-Protocol-Version`

Type: string. Requirement: required.

Required exact current version selector. Send one value equal to \`1.0\`; every other value is unsupported.

#### `Authorization`

Type: header. Requirement: required.

Bearer token for authenticated platform requests.

-   example: Bearer YOUR\_API\_KEY

#### `Content-Type`

Type: header. Requirement: required.

Request body format for JSON endpoints.

-   example: application/json

#### `x-aon-user-pseudo-id`

Type: string. Requirement: optional.

Optional 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-xyz

#### `x-aon-consent`

Type: string. Requirement: optional.

Optional 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=verified

Request Body

JSON payload fields accepted by this endpoint.

#### `context`

Type: object. Requirement: required.

Bounded calling and session context for the current Query. It is not a raw conversation transcript or long-term profile.

#### `context.platform`

Type: object. Requirement: optional.

Calling platform or agent metadata used for diagnostics and integration context.

-   example: { "name": "shopping-bot", "channel": "api" }

#### `context.platform.name`

Type: string. Requirement: optional.

Optional non-empty name of the calling platform or agent.

-   example: shopping-bot

#### `context.platform.version`

Type: string. Requirement: optional.

Optional caller-reported platform or agent version used for integration diagnostics.

-   example: 2.1.0

#### `context.platform.channel`

Type: string. Requirement: optional.

Optional caller-reported interaction channel.

-   example: api

#### `context.session`

Type: object. Requirement: optional.

Bounded session continuity for the current conversation.

-   example: { "previous\_request\_id": "019dd200-1234-7890-abcd-ef0123456788" }

#### `context.session.previous_request_id`

Type: string. Requirement: optional.

Optional Query response identifier used as the explicit comparison baseline for returned hooks.

-   example: 019dd200-1234-7890-abcd-ef0123456788
-   format: uuid

#### `context.session.recent_topics`

Type: string\[\]. Requirement: optional.

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"\]

#### `context.session_id`

Type: string. Requirement: optional.

Optional session identifier for support correlation.

-   example: sess\_123
-   maxLength: 256

#### `context.conversation_id`

Type: string | number. Requirement: optional.

Optional host conversation identifier.

-   example: conversation\_123

#### `intent`

Type: object. Requirement: required.

The user's current intent for this Query, not the complete conversation history.

#### `intent.details`

Type: object. Requirement: optional.

Explicit opt-in Flight search constraints.

#### `intent.details.profile`

Type: string. Requirement: required when intent.details is present.

Registered Query profile identifier.

Allowed values: `flight`

#### `intent.details.data`

Type: object. Requirement: required when intent.details is present.

Closed hard constraints for a typed Flight search.

#### `intent.details.data.query_kind`

Type: string. Requirement: required when intent.details.data is present.

Explicit reference search or traveler-specific full itinerary quote; no inferred default.

Allowed values: `reference_search`, `traveler_quote`

#### `intent.details.data.legs[]`

Type: object\[\]. Requirement: required when intent.details.data is present.

Nonempty itinerary legs in request order.

#### `intent.details.data.legs[].origin`

Type: object. Requirement: required when intent.details.data.legs\[\] is present.

Requested departure airport or city.

#### `intent.details.data.legs[].origin.kind`

Type: string. Requirement: required when intent.details.data.legs\[\].origin is present.

Whether the requested code denotes an airport or city.

Allowed values: `airport`, `city`

#### `intent.details.data.legs[].origin.code`

Type: string. Requirement: required when intent.details.data.legs\[\].origin is present.

Three-letter uppercase location code; spelling alone does not prove registry membership.

-   pattern: ^\[A-Z\]{3}$

#### `intent.details.data.legs[].destination`

Type: object. Requirement: required when intent.details.data.legs\[\] is present.

Requested arrival airport or city.

#### `intent.details.data.legs[].destination.kind`

Type: string. Requirement: required when intent.details.data.legs\[\].destination is present.

Whether the requested code denotes an airport or city.

Allowed values: `airport`, `city`

#### `intent.details.data.legs[].destination.code`

Type: string. Requirement: required when intent.details.data.legs\[\].destination is present.

Three-letter uppercase location code; spelling alone does not prove registry membership.

-   pattern: ^\[A-Z\]{3}$

#### `intent.details.data.legs[].departure_date`

Type: string. Requirement: required when intent.details.data.legs\[\] is present.

Actual calendar date at the departure location in YYYY-MM-DD form.

-   format: date
-   pattern: ^\[0-9\]{4}-\[0-9\]{2}-\[0-9\]{2}$

#### `intent.details.data.travelers[]`

Type: object\[\]. Requirement: required when query\_kind is traveler\_quote (forbidden for reference\_search).

Traveler groups, required for a quote and forbidden for a reference search. Typed Flight quotes require matching traveler composition.

#### `intent.details.data.travelers[].type`

Type: string. Requirement: required when intent.details.data.travelers\[\] is present.

Traveller type used to state the priced traveller composition.

Allowed values: `adult`, `child`, `infant`

#### `intent.details.data.travelers[].count`

Type: integer. Requirement: required when intent.details.data.travelers\[\] is present.

Positive number of travellers of this type included in the stated itinerary price.

-   minimum: 1

#### `intent.details.data.travelers[].ages`

Type: integer\[\]. Requirement: required when traveler type is child or infant.

Completed years of age on the first local departure date, in traveler order. Supply one age per traveler.

#### `intent.details.data.travelers[].infant_seat_required`

Type: boolean\[\]. Requirement: required when traveler type is infant.

Seat requirement for each infant at the same index as ages. Supply one seat flag per infant; forbidden for other traveler types.

#### `intent.details.data.cabin_class`

Type: string. Requirement: optional.

Exact cabin required on every returned segment.

Allowed values: `economy`, `premium_economy`, `business`, `first`

#### `intent.details.data.max_connections`

Type: integer. Requirement: optional.

Maximum segment changes within each leg.

-   minimum: 0

#### `intent.details.data.nonstop_only`

Type: boolean. Requirement: optional.

When true, each leg must contain one segment with explicitly empty stops.

#### `intent.content[]`

Type: object\[\]. Requirement: required.

Exactly one current text or image input item.

-   example: { "type": "input\_text", "text": "noise cancelling headphones under $200" }

#### `intent.content[].type`

Type: string. Requirement: required.

Content item kind. Most server integrations start with \`input\_text\`.

-   example: input\_text

Allowed values: `input_text`, `input_image`

#### `intent.content[].text`

Type: string. Requirement: required when intent.content\[\].type is input\_text.

Free-text user intent when the item type is \`input\_text\`.

-   example: noise cancelling headphones under $200
-   minLength: 1
-   maxLength: 200

#### `intent.content[].image_url`

Type: string. Requirement: required when intent.content\[\].type is input\_image.

URI of the current image input for an input\_image item.

-   example: https://example.com/current-product.jpg
-   format: uri

#### `intent.provenance`

Type: string. Requirement: required.

Whether the current intent was directly expressed by the user or inferred from context.

-   example: user\_expressed

Allowed values: `user_expressed`, `inferred_context`

#### `intent.confidence`

Type: number. Requirement: required when intent.provenance is inferred\_context.

Confidence assigned to an inferred intent. It is required for inferred\_context and forbidden for user\_expressed intent.

-   example: 0.8
-   minimum: 0
-   maximum: 1

#### `intent.origin[]`

Type: object\[\]. Requirement: optional.

At most three unique references that led to a user-expressed intent. Inferred intent cannot carry origin entries.

#### `intent.origin[].kind`

Type: string. Requirement: required when the origin item is present.

Kind of source reference that led to the current intent.

Allowed values: `offer`, `category`, `topic`, `query_helper`

#### `intent.origin[].id`

Type: string. Requirement: required when the origin item is present.

Opaque identifier of the referenced source within its declared kind.

-   minLength: 1
-   maxLength: 256

#### `intent.signals`

Type: object. Requirement: optional.

Structured signals for the current turn, such as purchase stage, timeframe, or a budget with an explicit currency.

#### `intent.signals.budget`

Type: object. Requirement: optional.

Numeric budget values require an explicit ISO 4217 currency; never infer the currency from language, region, or device.

-   example: { "max": 200, "currency": "USD" }

#### `intent.signals.budget.max`

Type: number. Requirement: required when intent.signals.budget is present.

Required non-negative upper budget bound in the declared budget currency.

-   example: 200
-   minimum: 0

#### `intent.signals.budget.currency`

Type: string. Requirement: required when intent.signals.budget is present.

Required uppercase three-letter currency code for every numeric budget declaration.

-   example: USD
-   pattern: ^\[A-Z\]{3}$

#### `intent.signals.budget.min`

Type: number. Requirement: optional.

Optional non-negative lower budget bound in the declared budget currency.

-   example: 100
-   minimum: 0

#### `intent.signals.purchase_stage`

Type: string. Requirement: optional.

Optional current stage in the user's purchase journey.

Allowed values: `exploring`, `comparing`, `ready_to_buy`

#### `intent.signals.timeframe`

Type: string. Requirement: optional.

Optional timeframe in which the user expects to act.

Allowed values: `now`, `this_week`, `this_month`, `later`

#### `request_id`

Type: string. Requirement: optional.

Optional client request identifier for log correlation. UUIDv7 is recommended.

-   example: 019dd200-1234-7890-abcd-ef0123456789
-   format: uuid

#### `timestamp`

Type: string. Requirement: optional.

Optional RFC 3339 timestamp for when the request was created.

-   example: 2026-04-28T03:30:00Z
-   format: date-time

#### `test_mode`

Type: boolean. Requirement: optional.

Optional test-execution marker that defaults to false. Deployments may apply stricter credential or environment controls.

-   example: false

#### `placement_id`

Type: string. Requirement: optional.

Optional top-level body field for platform-defined placement routing. Do not send it as a URL query parameter or under \`constraints\`.

-   example: plc\_A1b2C3d4E5f6G7h8
-   minLength: 1
-   maxLength: 64
-   pattern: ^\\S+$

#### `constraints`

Type: object. Requirement: optional.

Explicit public taxonomy constraints for the current Query.

#### `constraints.category_ids[]`

Type: string\[\]. Requirement: optional.

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: others

#### `constraints.excluded_category_ids[]`

Type: string\[\]. Requirement: optional.

AON Taxonomy v1 category ids to exclude from the current query. Parent ids exclude descendant offer categories.

-   example: arts\_entertainment.adult\_entertainment

#### `force_offer`

Type: boolean. Requirement: optional.

Request a fallback recommendation when normal matching returns no offer.

-   example: false

#### `response_options`

Type: object. Requirement: optional.

Optional controls for the shape of the current Query response.

#### `response_options.thinking_mode`

Type: boolean. Requirement: optional.

Defaults to true. Set false when the client does not want \`match\_reason\` in returned offers.

-   example: true

Request Examples

#### Minimal request

```json
{
  "intent": {
    "content": [
      {
        "type": "input_text",
        "text": "noise cancelling headphones under $200"
      }
    ],
    "provenance": "user_expressed"
  },
  "context": {
    "platform": { "name": "api-client", "channel": "api" }
  }
}
```

#### Production request

```json
{
  "request_id": "019dd200-1234-7890-abcd-ef0123456789",
  "timestamp": "2026-04-28T03:30:00Z",
  "test_mode": false,
  "placement_id": "plc_A1b2C3d4E5f6G7h8",
  "intent": {
    "content": [
      {
        "type": "input_text",
        "text": "Find me a luxury hotel in Tokyo under $300/night for a weekend trip"
      }
    ],
    "provenance": "user_expressed",
    "signals": {
      "budget": { "max": 300, "currency": "USD" },
      "timeframe": "this_week"
    }
  },
  "context": {
    "platform": {
      "name": "TravelBot",
      "channel": "telegram",
      "version": "2.1.0"
    },
    "session": { "recent_topics": ["Tokyo hotels"] },
    "conversation_id": "conversation_123"
  },
  "constraints": {
    "category_ids": ["travel_tourism"]
  },
  "force_offer": false,
  "response_options": { "thinking_mode": true }
}
```

### Response

Current 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.

#### `code`

Type: string. Requirement: required.

No description provided by the current OpenAPI source.

#### `message`

Type: string. Requirement: required.

No description provided by the current OpenAPI source.

#### `data`

Type: object. Requirement: required.

No description provided by the current OpenAPI source.

#### `data.request_id`

Type: string. Requirement: required.

Request identifier echoed from the accepted query. AON injects one when the client omits it.

-   example: 019dd200-1234-7890-abcd-ef0123456789
-   format: uuid

#### `data.protocol_version`

Type: string. Requirement: required.

Transport protocol line used to produce the response. This is always \`1.0\` for the current lane and is distinct from \`offers\[\].version\`.

-   example: 1.0

Allowed values: `1.0`

#### `data.language`

Type: string. Requirement: required.

Language selected for user-facing response content under the stable-v1.0 language-tag profile. It does not express eligibility or targeting.

-   example: en
-   format: bcp47

#### `data.offers[]`

Type: object\[\]. Requirement: required.

Ranked offers that matched the request. Empty array means no eligible offer.

#### `data.offers[].offer_id`

Type: string. Requirement: required.

AON-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-699c243e6c96
-   format: uuid

#### `data.offers[].offer_instance_id`

Type: string. Requirement: required.

AON-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.

-   example: 019dd208-27d2-7673-b16f-6897fa120303
-   format: uuid

#### `data.offers[].version`

Type: string. Requirement: required.

Offer document-model lineage. It identifies the Offer payload model and does not select the transport protocol version.

-   example: 3.0

Allowed values: `3.0`

#### `data.offers[].offer_info`

Type: object. Requirement: required.

User-facing descriptive, category, commercial, and availability information for the Offer.

#### `data.offers[].offer_info.details`

Type: object. Requirement: required when intent.details.profile is flight.

Registered Offer profile facts; optional on ordinary and non-real-time Query results, required for typed Flight results. Details do not imply a live lookup.

#### `data.offers[].offer_info.details.profile`

Type: string. Requirement: required when data.offers\[\].offer\_info.details is present.

Registered Offer profile; validated independently of real-time query selection.

Allowed values: `flight`, `hotel_rate`

#### `data.offers[].offer_info.details.data`

Type: object. Requirement: required when data.offers\[\].offer\_info.details is present.

Closed facts for the selected registered Offer profile. Flight fields below describe one priced air itinerary.

#### `data.offers[].offer_info.details.data.trip_type`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data is present.

Declared itinerary topology; semantic validation binds it to the number of legs.

Allowed values: `one_way`, `round_trip`, `multi_city`

#### `data.offers[].offer_info.details.data.travelers[]`

Type: object\[\]. Requirement: required when query\_kind is traveler\_quote (forbidden for reference\_search).

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.

#### `data.offers[].offer_info.details.data.travelers[].type`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.travelers\[\] is present.

Traveller type used to state the priced traveller composition.

Allowed values: `adult`, `child`, `infant`

#### `data.offers[].offer_info.details.data.travelers[].count`

Type: integer. Requirement: required when data.offers\[\].offer\_info.details.data.travelers\[\] is present.

Positive number of travellers of this type included in the stated itinerary price.

-   minimum: 1

#### `data.offers[].offer_info.details.data.travelers[].ages`

Type: integer\[\]. Requirement: required when traveler type is child or infant.

Completed years of age on the first local departure date, in traveler order. Supply one age per traveler.

#### `data.offers[].offer_info.details.data.travelers[].infant_seat_required`

Type: boolean\[\]. Requirement: required when traveler type is infant.

Seat requirement for each infant at the same index as ages. Supply one seat flag per infant; forbidden for other traveler types.

#### `data.offers[].offer_info.details.data.legs[]`

Type: object\[\]. Requirement: required when data.offers\[\].offer\_info.details.data is present.

Ordered itinerary legs. Each leg contains one or more ordered flight segments.

#### `data.offers[].offer_info.details.data.legs[].segments[]`

Type: object\[\]. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\] is present.

Ordered segments for this leg. Semantic validation requires adjacent arrival and departure continuity.

#### `data.offers[].offer_info.details.data.legs[].segments[].departure`

Type: object. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\] is present.

Scheduled departure airport and airport-local date-time for this segment.

#### `data.offers[].offer_info.details.data.legs[].segments[].departure.airport_code`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\].departure is present.

Three-letter uppercase airport code; airport-registry membership is outside this profile.

-   pattern: ^\[A-Z\]{3}$

#### `data.offers[].offer_info.details.data.legs[].segments[].departure.local_at`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\].departure is present.

Scheduled 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\]$

#### `data.offers[].offer_info.details.data.legs[].segments[].arrival`

Type: object. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\] is present.

Scheduled arrival airport and airport-local date-time for this segment.

#### `data.offers[].offer_info.details.data.legs[].segments[].arrival.airport_code`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\].arrival is present.

Three-letter uppercase airport code; airport-registry membership is outside this profile.

-   pattern: ^\[A-Z\]{3}$

#### `data.offers[].offer_info.details.data.legs[].segments[].arrival.local_at`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\].arrival is present.

Scheduled 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\]$

#### `data.offers[].offer_info.details.data.legs[].segments[].duration_minutes`

Type: integer. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\] is present.

Positive 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: 1

#### `data.offers[].offer_info.details.data.legs[].segments[].marketing_carrier`

Type: object. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\] is present.

Carrier marketing this flight under the displayed flight number.

#### `data.offers[].offer_info.details.data.legs[].segments[].marketing_carrier.code`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\].marketing\_carrier is present.

Two-character uppercase marketing carrier code; registry membership is not asserted by this profile.

-   pattern: ^\[A-Z0-9\]{2}$

#### `data.offers[].offer_info.details.data.legs[].segments[].flight_number`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\] is present.

Carrier-local flight number without the marketing-carrier prefix.

-   pattern: ^\[0-9\]{1,4}\[A-Z\]?$

#### `data.offers[].offer_info.details.data.legs[].segments[].cabin_class`

Type: string. Requirement: required when data.offers\[\].offer\_info.details.data.legs\[\].segments\[\] is present.

Public cabin class for this segment.

Allowed values: `economy`, `premium_economy`, `business`, `first`

#### `data.offers[].offer_info.details.data.legs[].segments[].stops[]`

Type: object\[\]. Requirement: optional.

Source-reported stops within this segment. Omission means unknown; an empty array explicitly means no stops.

#### `data.offers[].offer_info.details.data.legs[].segments[].stops[].name`

Type: string. Requirement: required when the stop is present and airport\_code is absent.

Source-provided nonblank location label, which may identify a city rather than an airport.

-   minLength: 1
-   pattern: \\S

#### `data.offers[].offer_info.details.data.legs[].segments[].stops[].airport_code`

Type: string. Requirement: required when the stop is present and name is absent.

Source-provided uppercase airport code; do not infer it from a location name.

-   pattern: ^\[A-Z\]{3}$

#### `data.offers[].offer_info.details.data.legs[].segments[].stops[].duration_minutes`

Type: integer. Requirement: optional.

Positive source-provided stop duration in minutes.

-   minimum: 1

#### `data.offers[].offer_info.details.data.legs[].duration_minutes`

Type: integer. Requirement: optional.

Source-provided total leg duration including connection waiting, at least the sum of segment durations.

-   minimum: 1

#### `data.offers[].offer_info.details.data.price_basis`

Type: string. Requirement: required when intent.details.profile is flight.

Price nature: a reference amount without traveler composition or a complete itinerary total.

Allowed values: `reference`, `itinerary_total`

#### `data.offers[].offer_info.title`

Type: string. Requirement: required.

Short user-facing name used to identify the Offer in a result or presentation.

-   example: QuietPro 500 Headphones

#### `data.offers[].offer_info.description`

Type: string. Requirement: required.

User-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.

#### `data.offers[].offer_info.category`

Type: object. Requirement: required.

Primary AON Taxonomy v1 classification for the Offer.

#### `data.offers[].offer_info.category.id`

Type: string. Requirement: required.

Canonical AON Taxonomy v1 identifier for the Offer's primary classification. Resolve ids from /protocol/category-taxonomy.

-   example: travel\_tourism.accommodations.hotels\_motels\_resorts.hotels

#### `data.offers[].offer_info.rating`

Type: object. Requirement: optional.

Optional user-visible rating summary supplied with the Offer. It is descriptive content and not an AON endorsement.

#### `data.offers[].offer_info.rating.value`

Type: number. Requirement: required when offer\_info.rating is present.

Rating value on the declared five-point scale.

-   example: 4.6
-   minimum: 0
-   maximum: 5

#### `data.offers[].offer_info.rating.count`

Type: integer. Requirement: optional.

Positive number of observations represented by the rating when supplied.

-   example: 128
-   minimum: 1

#### `data.offers[].offer_info.rating.source`

Type: string. Requirement: optional.

Optional name of the source that supplied the rating.

-   example: Verified customers

#### `data.offers[].offer_info.properties[]`

Type: object\[\]. Requirement: optional.

Optional non-empty, bounded list of structured user-facing facts, such as duration, plan tier, or included features.

#### `data.offers[].offer_info.properties[].type`

Type: string. Requirement: required when the properties item is present.

Stable machine-readable key for the displayed fact.

-   example: plan\_tier

#### `data.offers[].offer_info.properties[].value`

Type: string | number | boolean. Requirement: required when the properties item is present.

Value of the displayed fact.

-   example: pro

#### `data.offers[].offer_info.properties[].unit`

Type: string. Requirement: optional.

Optional non-empty unit that qualifies the displayed value.

-   example: month

#### `data.offers[].offer_info.properties[].display_pattern`

Type: string. Requirement: optional.

Optional presentation template for this fact. Only same-item tokens \`${type}\`, \`${value}\`, and \`${unit}\` are allowed.

-   example: ${value} per ${unit}

#### `data.offers[].offer_info.commercial`

Type: object. Requirement: required when intent.details.profile is flight.

Public commercial presentation; required for typed Flight results and optional for Generic results. It excludes internal commission, settlement, and eligibility policy.

#### `data.offers[].offer_info.commercial.quote`

Type: object. Requirement: required when the returned Offer profile requires quote observation (including non-reference Flight and Hotel rates).

Observed 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.

#### `data.offers[].offer_info.commercial.quote.observed_at`

Type: string. Requirement: required when data.offers\[\].offer\_info.commercial.quote is present.

RFC 3339 instant at which the producer observed the original Offer price.

-   format: date-time

#### `data.offers[].offer_info.commercial.quote.valid_until`

Type: string. Requirement: optional.

Optional 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-time

#### `data.offers[].offer_info.commercial.price`

Type: object. Requirement: required when intent.details.profile is flight.

Original price; required for typed Flight results and optional for Generic results. Flight traveler\_quote requires an itinerary total including taxes and mandatory fees.

#### `data.offers[].offer_info.commercial.price.tax_status`

Type: string. Requirement: required when the returned Offer profile requires explicit tax status.

Original price tax and mandatory-fee status under the returned Offer profile; typed Flight traveler\_quote requires included.

Allowed values: `included`, `excluded`, `unknown`

#### `data.offers[].offer_info.commercial.price.amount`

Type: string. Requirement: required when offer\_info.commercial.price is present.

Canonical decimal string for the displayed public Offer price, not Goal commission.

-   example: 189.99

#### `data.offers[].offer_info.commercial.price.currency`

Type: string. Requirement: required when offer\_info.commercial.price is present.

Uppercase three-letter currency code for the displayed public Offer price.

-   example: USD
-   pattern: ^\[A-Z\]{3}$

#### `data.offers[].offer_info.commercial.price.unit`

Type: string. Requirement: optional.

Optional unit or billing period to which the displayed price applies. Typed Flight permits only one\_time.

-   example: month

Allowed values: `one_time`, `night`, `day`, `week`, `month`, `year`

#### `data.offers[].offer_info.commercial.display_price`

Type: object. Requirement: optional.

Optional 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.

#### `data.offers[].offer_info.commercial.display_price.amount`

Type: string. Requirement: required when offer\_info.commercial.display\_price is present.

Canonical non-negative decimal amount to present for this response, with at most twelve integer digits and six fractional digits.

-   example: 718.42
-   pattern: ^(?:0|\[1-9\]\[0-9\]{0,11})(?:\\.\[0-9\]{1,6})?$

#### `data.offers[].offer_info.commercial.display_price.currency`

Type: string. Requirement: required when offer\_info.commercial.display\_price is present.

Uppercase three-letter target presentation currency syntax; registry membership is not asserted.

-   example: CNY
-   pattern: ^\[A-Z\]{3}$

#### `data.offers[].offer_info.commercial.fulfillment_note`

Type: string. Requirement: optional.

Optional short user-facing note about fulfillment or a material price condition.

#### `data.offers[].offer_info.short_description`

Type: string. Requirement: optional.

Optional 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: 500

#### `data.offers[].offer_info.offer_type`

Type: string. Requirement: optional.

High-level class of what is offered. It supports presentation and product understanding; it is not the executable consumer action.

-   example: online\_service

Allowed values: `physical_product`, `digital_goods`, `content`, `online_service`, `offline_service`

#### `data.offers[].offer_info.secondary_category_ids`

Type: string\[\]. Requirement: optional.

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"\]

#### `data.offers[].offer_info.tags`

Type: string\[\]. Requirement: optional.

Optional non-empty set of short descriptive labels for presentation or filtering. Tags do not replace canonical taxonomy classification or targeting rules.

-   example: \["project-management", "team-collaboration", "free-trial"\]

#### `data.offers[].offer_info.recommendation_reason`

Type: string. Requirement: optional.

Optional static Partner- or provider-authored Offer copy. It is not the per-request AON match explanation and is unaffected by thinking\_mode.

#### `data.offers[].offer_info.start_at`

Type: string. Requirement: optional.

Optional start of the user-visible Offer availability window.

-   format: date-time

#### `data.offers[].offer_info.expire_at`

Type: string. Requirement: optional.

Optional end of the user-visible Offer availability window. When both bounds are supplied, it must not precede start\_at.

-   format: date-time

#### `data.offers[].entity`

Type: object. Requirement: required.

Public identity of the party responsible for the Offer.

#### `data.offers[].entity.id`

Type: string. Requirement: required.

Stable identifier for the merchant, brand, provider, publisher, or other party responsible for the Offer. It is not an Offer identifier.

-   example: ent\_audiomart

#### `data.offers[].entity.name`

Type: string. Requirement: required.

User-facing name of the entity responsible for the Offer.

-   example: AudioMart

#### `data.offers[].entity.type`

Type: string. Requirement: optional.

Role of the entity in relation to the Offer.

-   example: provider

Allowed values: `merchant`, `brand`, `provider`, `publisher`, `other`

#### `data.offers[].entity.description`

Type: string. Requirement: optional.

Optional non-empty user-facing description of the responsible entity.

-   example: Consumer electronics retailer.

#### `data.offers[].entity.website`

Type: string. Requirement: optional.

Optional 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.example
-   format: uri
-   pattern: ^\[Hh\]\[Tt\]\[Tt\]\[Pp\]\[Ss\]://

#### `data.offers[].entity.logo`

Type: string. Requirement: optional.

Optional 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.png
-   format: uri
-   pattern: ^\[Hh\]\[Tt\]\[Tt\]\[Pp\]\[Ss\]://

#### `data.offers[].listing_source`

Type: object. Requirement: optional.

Optional provenance for the external platform or site where listing information was observed.

#### `data.offers[].listing_source.kind`

Type: string. Requirement: required when listing\_source is present.

Classification of the external place where user-facing listing information was observed.

Allowed values: `platform`, `marketplace`, `merchant_site`, `official_site`, `other`

#### `data.offers[].listing_source.name`

Type: string. Requirement: required when listing\_source is present.

User-facing name of the observed platform or site. It remains distinct from entity.name.

#### `data.offers[].listing_source.observed_at`

Type: string. Requirement: required when listing\_source is present.

UTC timestamp for when the listing information was observed, not the Offer availability window.

-   format: date-time

#### `data.offers[].listing_source.logo`

Type: string. Requirement: optional.

Optional 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: uri
-   pattern: ^\[Hh\]\[Tt\]\[Tt\]\[Pp\]\[Ss\]://

#### `data.offers[].material[]`

Type: object\[\]. Requirement: optional.

Optional non-empty list of user-facing creative assets for presenting the Offer. It is distinct from entity.logo and listing\_source.logo.

#### `data.offers[].material[].url`

Type: string. Requirement: required when the material item is present.

Absolute HTTPS URI for retrieving the creative asset; URI userinfo is forbidden.

-   example: https://example.com/assets/quietpro-500-hero.jpg
-   format: uri
-   pattern: ^\[Hh\]\[Tt\]\[Tt\]\[Pp\]\[Ss\]://

#### `data.offers[].material[].format`

Type: string. Requirement: required when the material item is present.

Creative asset format.

-   example: image

Allowed values: `image`, `video`, `html5`

#### `data.offers[].material[].tag`

Type: string. Requirement: optional.

Optional producer-supplied label for the creative asset. It must not be treated as targeting or eligibility data.

-   example: hero

#### `data.offers[].material[].dimensions`

Type: string. Requirement: optional.

Optional producer-declared dimensions or aspect descriptor for rendering.

-   example: 1200x628

#### `data.offers[].material[].alt_text`

Type: string. Requirement: optional.

Optional accessibility text describing the creative asset.

#### `data.offers[].action`

Type: object. Requirement: required.

Executable user-choice destination associated with the Offer.

#### `data.offers[].action.type`

Type: string. Requirement: required.

Technical form of the executable action destination.

-   example: open\_url

Allowed values: `open_url`, `deep_link`, `open_app`, `custom`

#### `data.offers[].action.payload`

Type: object. Requirement: required.

Executable action parameters. Stable v1.0 defines one safe absolute URI destination.

#### `data.offers[].action.payload.url`

Type: string. Requirement: required.

Safe 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-500
-   format: uri
-   pattern: ^(?!(?:\[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+.-\]\*:

#### `data.offers[].action.name`

Type: string. Requirement: optional.

Optional non-empty concise call-to-action label for the user.

-   example: Shop now

#### `data.offers[].action.consumer_action`

Type: string. Requirement: optional.

User-intent classification for the action. It describes what the user is invited to do and is distinct from a conversion Goal event.

-   example: buy

Allowed values: `learn_more`, `buy`, `book`, `subscribe`, `download`, `claim`, `sign_up`, `open`

#### `data.offers[].action.description`

Type: string. Requirement: optional.

Optional non-empty user-facing explanation of what invoking the action does.

-   example: Open the product page on the merchant site.

#### `data.offers[].action.destination_types`

Type: string\[\]. Requirement: optional.

Optional non-empty declaration of destination surfaces supported by the action. It does not replace action.type or payload.url.

-   example: web

Allowed values: `web`, `app`, `phone`, `email`

#### `data.offers[].goals[]`

Type: object\[\]. Requirement: required.

Public conversion event declarations and their associated public pricing model.

#### `data.offers[].goals[].event`

Type: string. Requirement: required.

Canonical conversion event name for this Goal; events are unique within one Offer.

-   example: conversion
-   pattern: ^\[a-z\]\[a-z0-9\_\]{0,63}$

#### `data.offers[].goals[].pricing`

Type: object. Requirement: required.

Gross commission the Partner declares payable to AON for an approved, attributed occurrence of this Goal, before fees, developer share, refunds, holds, disputes, or adjustments.

#### `data.offers[].goals[].pricing.model`

Type: string. Requirement: required.

Gross 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: cpa

Allowed values: `cpa`, `cps`

#### `data.offers[].goals[].pricing.amount`

Type: string. Requirement: required when pricing.model is cpa.

Strictly positive canonical decimal amount of gross Partner-to-AON commission for one approved Goal event.

-   example: 10
-   pattern: ^(?:0|\[1-9\]\[0-9\]{0,11})(?:\\.\[0-9\]{1,6})?$
-   excluded: 0, 0.0, 0.00, 0.000, 0.0000, 0.00000, 0.000000

#### `data.offers[].goals[].pricing.currency`

Type: string. Requirement: required when pricing.model is cpa.

Uppercase three-letter currency code for the CPA commission amount.

-   example: USD
-   pattern: ^\[A-Z\]{3}$

#### `data.offers[].goals[].pricing.rate`

Type: string. Requirement: required when pricing.model is cps.

Strictly positive canonical percentage rate, greater than zero and no greater than 100, applied to the gross conversion amount in its reported currency.

-   example: 12.5
-   pattern: ^(?:100(?:\\.0{1,4})?|\[1-9\]?\[0-9\](?:\\.\[0-9\]{1,4})?)$
-   excluded: 0, 0.0, 0.00, 0.000, 0.0000

#### `data.offers[].goals[].description`

Type: string. Requirement: optional.

Optional user-facing explanation of what outcome constitutes the Goal; it does not change attribution or payment terms.

#### `data.offers[].claims[]`

Type: object\[\]. Requirement: optional.

Optional non-empty, bounded list of source-provided statements about the Offer. They are not AON endorsements.

#### `data.offers[].claims[].kind`

Type: string. Requirement: required when the claim item is present.

Classification of the statement so consumers can present it with appropriate context.

Allowed values: `advertiser_claim`, `user_benefit`, `availability`

#### `data.offers[].claims[].text`

Type: string. Requirement: required when the claim item is present.

User-facing statement text. It remains source-provided content, not an AON endorsement.

#### `data.offers[].content_language`

Type: string. Requirement: optional.

Language 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-US
-   format: bcp47

#### `data.offers[].match_reason`

Type: string. Requirement: optional.

AON-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.

#### `data.engagement`

Type: object. Requirement: optional.

Optional non-empty user-facing guidance for refining the current intent or exploring an adjacent topic. It does not change returned Offers.

#### `data.engagement.refinements[]`

Type: object\[\]. Requirement: optional.

Up to three non-empty suggestions that narrow or clarify the current Query intent.

#### `data.engagement.refinements[].label`

Type: string. Requirement: required when the refinement item is present.

Short user-facing label for the refinement.

-   minLength: 1
-   maxLength: 160

#### `data.engagement.refinements[].query_helper`

Type: object. Requirement: required when the refinement item is present.

Structured and bounded instruction for deriving a subsequent Query without deleting current request fields.

#### `data.engagement.refinements[].query_helper.request_patch`

Type: object. Requirement: required when the query\_helper is present.

Required non-empty partial update limited to intent.signals and category constraints. Omission preserves values, objects merge, arrays replace, and null is invalid.

#### `data.engagement.refinements[].query_helper.request_patch.intent`

Type: object. Requirement: optional.

Optional intent portion of the next-Query update; when present it contains non-empty signals.

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals`

Type: object. Requirement: required when request\_patch.intent is present.

Non-empty intent signals proposed for the next Query. Omitted signal members remain unchanged.

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals.budget`

Type: object. Requirement: optional.

Optional budget update with an explicit upper bound and currency.

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals.budget.max`

Type: number. Requirement: required when the budget update is present.

Required non-negative replacement upper budget bound.

-   minimum: 0

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals.budget.currency`

Type: string. Requirement: required when the budget update is present.

Required uppercase three-letter currency code for the budget update.

-   pattern: ^\[A-Z\]{3}$

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals.budget.min`

Type: number. Requirement: optional.

Optional non-negative replacement lower budget bound.

-   minimum: 0

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals.purchase_stage`

Type: string. Requirement: optional.

Optional replacement purchase-journey stage.

Allowed values: `exploring`, `comparing`, `ready_to_buy`

#### `data.engagement.refinements[].query_helper.request_patch.intent.signals.timeframe`

Type: string. Requirement: optional.

Optional replacement action timeframe.

Allowed values: `now`, `this_week`, `this_month`, `later`

#### `data.engagement.refinements[].query_helper.request_patch.constraints`

Type: object. Requirement: optional.

Non-empty category-constraint update. Supplied arrays replace prior arrays, including an empty array that clears a constraint.

#### `data.engagement.refinements[].query_helper.request_patch.constraints.category_ids[]`

Type: string\[\]. Requirement: optional.

Replacement list of included AON Taxonomy v1 category ids.

#### `data.engagement.refinements[].query_helper.request_patch.constraints.excluded_category_ids[]`

Type: string\[\]. Requirement: optional.

Replacement list of excluded AON Taxonomy v1 category ids.

#### `data.engagement.refinements[].query_helper.origin[]`

Type: object\[\]. Requirement: optional.

Optional non-empty provenance references to copy into intent.origin if the user adopts this suggestion.

#### `data.engagement.refinements[].query_helper.origin[].kind`

Type: string. Requirement: required when the query\_helper origin item is present.

Kind of source reference for the suggested next Query.

Allowed values: `offer`, `category`, `topic`, `query_helper`

#### `data.engagement.refinements[].query_helper.origin[].id`

Type: string. Requirement: required when the query\_helper origin item is present.

Opaque identifier of the suggested Query source within its declared kind.

-   minLength: 1
-   maxLength: 256

#### `data.engagement.refinements[].speak`

Type: string. Requirement: optional.

Optional longer phrasing suitable for voice or conversational presentation.

-   minLength: 1
-   maxLength: 500

#### `data.engagement.followup_topics[]`

Type: object\[\]. Requirement: optional.

Up to two adjacent-topic suggestions ordered by descending confidence within this response.

#### `data.engagement.followup_topics[].label`

Type: string. Requirement: required when the follow-up topic item is present.

Short user-facing label for the related topic.

-   minLength: 1
-   maxLength: 160

#### `data.engagement.followup_topics[].basis`

Type: string. Requirement: required when the follow-up topic item is present.

Declared relationship between the follow-up topic and the current Query.

Allowed values: `category_complement`, `sequential_journey`, `problem_to_product`, `comparison_alternative`, `user_interest`, `seasonal`

#### `data.engagement.followup_topics[].query_helper`

Type: object. Requirement: required when the follow-up topic item is present.

Structured and bounded instruction for deriving a subsequent Query without deleting current request fields.

#### `data.engagement.followup_topics[].query_helper.request_patch`

Type: object. Requirement: required when the query\_helper is present.

Required non-empty partial update limited to intent.signals and category constraints. Omission preserves values, objects merge, arrays replace, and null is invalid.

#### `data.engagement.followup_topics[].query_helper.request_patch.intent`

Type: object. Requirement: optional.

Optional intent portion of the next-Query update; when present it contains non-empty signals.

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals`

Type: object. Requirement: required when request\_patch.intent is present.

Non-empty intent signals proposed for the next Query. Omitted signal members remain unchanged.

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals.budget`

Type: object. Requirement: optional.

Optional budget update with an explicit upper bound and currency.

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals.budget.max`

Type: number. Requirement: required when the budget update is present.

Required non-negative replacement upper budget bound.

-   minimum: 0

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals.budget.currency`

Type: string. Requirement: required when the budget update is present.

Required uppercase three-letter currency code for the budget update.

-   pattern: ^\[A-Z\]{3}$

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals.budget.min`

Type: number. Requirement: optional.

Optional non-negative replacement lower budget bound.

-   minimum: 0

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals.purchase_stage`

Type: string. Requirement: optional.

Optional replacement purchase-journey stage.

Allowed values: `exploring`, `comparing`, `ready_to_buy`

#### `data.engagement.followup_topics[].query_helper.request_patch.intent.signals.timeframe`

Type: string. Requirement: optional.

Optional replacement action timeframe.

Allowed values: `now`, `this_week`, `this_month`, `later`

#### `data.engagement.followup_topics[].query_helper.request_patch.constraints`

Type: object. Requirement: optional.

Non-empty category-constraint update. Supplied arrays replace prior arrays, including an empty array that clears a constraint.

#### `data.engagement.followup_topics[].query_helper.request_patch.constraints.category_ids[]`

Type: string\[\]. Requirement: optional.

Replacement list of included AON Taxonomy v1 category ids.

#### `data.engagement.followup_topics[].query_helper.request_patch.constraints.excluded_category_ids[]`

Type: string\[\]. Requirement: optional.

Replacement list of excluded AON Taxonomy v1 category ids.

#### `data.engagement.followup_topics[].query_helper.origin[]`

Type: object\[\]. Requirement: optional.

Optional non-empty provenance references to copy into intent.origin if the user adopts this suggestion.

#### `data.engagement.followup_topics[].query_helper.origin[].kind`

Type: string. Requirement: required when the query\_helper origin item is present.

Kind of source reference for the suggested next Query.

Allowed values: `offer`, `category`, `topic`, `query_helper`

#### `data.engagement.followup_topics[].query_helper.origin[].id`

Type: string. Requirement: required when the query\_helper origin item is present.

Opaque identifier of the suggested Query source within its declared kind.

-   minLength: 1
-   maxLength: 256

#### `data.engagement.followup_topics[].confidence`

Type: number. Requirement: required when the follow-up topic item is present.

Producer-normalized relevance estimate. It is comparable only among follow-up topics in this response, not across requests or producers.

-   minimum: 0
-   maximum: 1

#### `data.hooks[]`

Type: object\[\]. Requirement: optional.

Optional change cues comparing a returned Offer with an explicit previous Query baseline. Hooks do not register watches or guarantee delivery.

#### `data.hooks[].kind`

Type: string. Requirement: required when the hook item is present.

Category of changed Offer information observed against the baseline.

Allowed values: `price_change`, `availability_change`, `eligibility_change`, `content_change`

#### `data.hooks[].title`

Type: string. Requirement: required when the hook item is present.

Short user-facing title for the change cue.

-   minLength: 1
-   maxLength: 160

#### `data.hooks[].subject_offer_id`

Type: string. Requirement: required when the hook item is present.

offer\_id of the returned Offer whose current representation is being compared.

-   format: uuid

#### `data.hooks[].baseline_request_id`

Type: string. Requirement: required when the hook item is present.

Prior Query response id used as the comparison baseline. It must equal the current request context.session.previous\_request\_id.

-   format: uuid

#### `data.hooks[].query_helper`

Type: object. Requirement: required when the hook carries an associated next-Query update.

Structured and bounded instruction for deriving a subsequent Query without deleting current request fields.

#### `data.hooks[].query_helper.request_patch`

Type: object. Requirement: required when the query\_helper is present.

Required non-empty partial update limited to intent.signals and category constraints. Omission preserves values, objects merge, arrays replace, and null is invalid.

#### `data.hooks[].query_helper.request_patch.intent`

Type: object. Requirement: optional.

Optional intent portion of the next-Query update; when present it contains non-empty signals.

#### `data.hooks[].query_helper.request_patch.intent.signals`

Type: object. Requirement: required when request\_patch.intent is present.

Non-empty intent signals proposed for the next Query. Omitted signal members remain unchanged.

#### `data.hooks[].query_helper.request_patch.intent.signals.budget`

Type: object. Requirement: optional.

Optional budget update with an explicit upper bound and currency.

#### `data.hooks[].query_helper.request_patch.intent.signals.budget.max`

Type: number. Requirement: required when the budget update is present.

Required non-negative replacement upper budget bound.

-   minimum: 0

#### `data.hooks[].query_helper.request_patch.intent.signals.budget.currency`

Type: string. Requirement: required when the budget update is present.

Required uppercase three-letter currency code for the budget update.

-   pattern: ^\[A-Z\]{3}$

#### `data.hooks[].query_helper.request_patch.intent.signals.budget.min`

Type: number. Requirement: optional.

Optional non-negative replacement lower budget bound.

-   minimum: 0

#### `data.hooks[].query_helper.request_patch.intent.signals.purchase_stage`

Type: string. Requirement: optional.

Optional replacement purchase-journey stage.

Allowed values: `exploring`, `comparing`, `ready_to_buy`

#### `data.hooks[].query_helper.request_patch.intent.signals.timeframe`

Type: string. Requirement: optional.

Optional replacement action timeframe.

Allowed values: `now`, `this_week`, `this_month`, `later`

#### `data.hooks[].query_helper.request_patch.constraints`

Type: object. Requirement: optional.

Non-empty category-constraint update. Supplied arrays replace prior arrays, including an empty array that clears a constraint.

#### `data.hooks[].query_helper.request_patch.constraints.category_ids[]`

Type: string\[\]. Requirement: optional.

Replacement list of included AON Taxonomy v1 category ids.

#### `data.hooks[].query_helper.request_patch.constraints.excluded_category_ids[]`

Type: string\[\]. Requirement: optional.

Replacement list of excluded AON Taxonomy v1 category ids.

#### `data.hooks[].query_helper.origin[]`

Type: object\[\]. Requirement: optional.

Optional non-empty provenance references to copy into intent.origin if the user adopts this suggestion.

#### `data.hooks[].query_helper.origin[].kind`

Type: string. Requirement: required when the query\_helper origin item is present.

Kind of source reference for the suggested next Query.

Allowed values: `offer`, `category`, `topic`, `query_helper`

#### `data.hooks[].query_helper.origin[].id`

Type: string. Requirement: required when the query\_helper origin item is present.

Opaque identifier of the suggested Query source within its declared kind.

-   minLength: 1
-   maxLength: 256

#### `data.hooks[].description`

Type: string. Requirement: optional.

Optional user-facing explanation of the observed change.

-   minLength: 1
-   maxLength: 500

#### `data.empty_reason`

Type: string. Requirement: required when data.offers is empty in a Generic Query response.

Primary 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 values: `frequency_capped`, `below_relevance_threshold`, `scene_suppressed`, `no_material`, `consent_missing`

#### `extra`

Type: object. Requirement: required.

No description provided by the current OpenAPI source.

#### `AON-Protocol-Version`

Type: string. Requirement: required.

HTTP response header that echoes the exact selected current Query protocol version on successful v1.0 responses.

-   example: 1.0

Allowed values: `1.0`

#### `X-AON-TRACE-ID`

Type: string. Requirement: optional.

HTTP response header for AON support diagnostics. It is not part of the JSON response body.

-   example: trc\_01HX6P8T4K2W9QX6Y7Z8A9BCDE

Response Examples

#### Success response

```json
{
  "code": "SUCCESS",
  "message": "",
  "data": {
    "request_id": "0195ef94-f17d-7a4f-b6e0-2c52bb49e13f",
    "protocol_version": "1.0",
    "language": "en",
    "offers": [
      {
        "offer_id": "019fc211-c6cd-7e62-9c4d-699c243e6c96",
        "offer_instance_id": "019fc211-c695-7bd2-9e1b-9a06c2952770",
        "version": "3.0",
        "content_language": "en",
        "offer_info": {
          "title": "TeamFlow Pro Plan",
          "offer_type": "online_service",
          "category": {
            "id": "computers_electronics.computers.software"
          },
          "description": "Collaborative workspace for docs, wikis, and project planning."
        },
        "entity": {
          "id": "ent_teamflow",
          "name": "TeamFlow"
        },
        "action": {
          "type": "open_url",
          "name": "Start free trial",
          "payload": {
            "url": "https://aon.link/oyMJZTta"
          }
        },
        "goals": [
          {
            "event": "conversion",
            "pricing": { "model": "cpa", "amount": "10", "currency": "USD" }
          }
        ]
      }
    ]
  },
  "extra": {}
}
```

#### Empty result response

```json
{
  "code": "SUCCESS",
  "message": "",
  "data": {
    "request_id": "019dd200-1234-7890-abcd-ef0123456789",
    "protocol_version": "1.0",
    "language": "en",
    "offers": [],
    "empty_reason": "below_relevance_threshold"
  },
  "extra": {}
}
```

### Errors

Errors and failure modes

#### 400: Bad Request

Malformed request body, unsupported field value, or invalid request shape.

##### Common causes

-   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.

##### Recommended handling

-   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.

#### 401: Unauthorized

Missing, expired, revoked, or invalid bearer credential.

##### Common causes

-   \`Authorization: Bearer <token>\` is missing.
-   The token belongs to the wrong account or environment.
-   The credential has been rotated or revoked.

##### Recommended handling

-   Create or rotate an API key from the developer app flow.
-   Confirm the request is sent to the matching staging or production base URL.

#### 429: Rate Limited

The integration exceeded the accepted request rate for the current window.

##### Common causes

-   A worker retried immediately in a loop.
-   Multiple sessions share the same key without backoff.

##### Recommended handling

-   Apply exponential backoff with jitter.
-   Respect retry windows when returned and avoid duplicate immediate retries.

#### INVALID\_PLACEMENT: Invalid Placement

Platform envelope error code for a malformed, empty, inactive, unauthorized, or unknown \`placement\_id\`. It is returned as the service envelope \`code\`, not as a canonical AgentOffer Protocol response payload field.

##### Common causes

-   \`placement\_id\` is empty, whitespace-only, malformed, inactive, missing, or belongs to another app.
-   The placement exists but is not available to the credential used for this request.

##### Recommended handling

-   Confirm the placement id was copied from the app's placement configuration.
-   Send placement as top-level JSON body field \`placement\_id\`, not as \`/v1/offers?placement\_id=...\` and not under \`constraints\`.

#### CATALOG\_NO\_AVAILABLE\_OFFERS: Catalog Has No Available Offers

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.

##### Common causes

-   The placement routes to an offerwall catalog data source.
-   The selected catalog currently has no active eligible offers.

##### Recommended handling

-   Review the catalog configuration and offer lifecycle state.
-   Retry only after inventory changes; immediate retries with the same placement should not change the result.

#### HTTP 400 Bad Request

```json
{
  "code": "BAD_REQUEST",
  "message": "intent.provenance is required",
  "data": {},
  "extra": {}
}
```

#### HTTP 401 Unauthorized

```json
{
  "code": "UNAUTHORIZED",
  "message": "Missing or invalid bearer token",
  "data": {},
  "extra": {}
}
```

#### HTTP 429 Too Many Requests

```json
{
  "code": "RATE_LIMITED",
  "message": "Rate limit exceeded. Retry after the returned window.",
  "data": {},
  "extra": {}
}
```

### 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\`. Missing, duplicate, historical, approximate, range, unknown, or any other non-exact selector returns HTTP 400 \`UNSUPPORTED\_PROTOCOL\_VERSION\`; no fallback is performed. 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. Optionally pass \`placement\_id\` to route the query by a configured ad placement; invalid placement values return \`INVALID\_PLACEMENT\` and an empty catalog placement returns \`CATALOG\_NO\_AVAILABLE\_OFFERS\`. 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 the first 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. 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\`.

-   This is the main partner entry point for offer discovery. Start here once bearer auth is working.
-   Persist \`offers\[\].offer\_instance\_id\` for downstream attribution and conversion reporting.
-   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 bearer auth and the required intent/context envelope.

-   Send `intent.content[]` with at least one user input item.
-   Include `intent.provenance` and 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.platform` and `context.session` for bounded continuity.
-   When your app has a placement context, send it as top-level body field `placement_id`.
-   Use `constraints.category_ids` when the user intent maps to AON Taxonomy v1.
-   Set `response_options.thinking_mode` to false when the client does not need match reasons.

### Empty result

Treat an empty \`offers\` array as a valid response. Show an empty state or relax constraints.

-   `code: SUCCESS` with `data.offers: []` is not an integration failure.
-   Log `data.request_id` before 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_PLACEMENT` and `CATALOG_NO_AVAILABLE_OFFERS` are platform envelope `code` values for placement-scoped queries.
-   Use 401 to check bearer token presence, account scope, or credential rotation.
-   Use 429 backoff with jitter and avoid immediate retry loops.

## Common Questions

### 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 \`Authorization: Bearer YOUR\_API\_KEY\` is present, the key belongs to the right account context, and the credential has not expired or been rotated.

### 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 \`placement\_id\`?

Send \`placement\_id\` as an optional top-level JSON body field on \`POST /v1/offers/query\`. Do not send it as \`/v1/offers?placement\_id=...\` and 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 an API key from Quick Start or Developer Portal first.
-   Send a structured \`intent\` payload, even for simple text-only queries.
-   Persist returned tracking URLs or identifiers for downstream attribution.

## Related links

[

Location Search

Optionally resolve registry ids for location pickers, normalization, or Offer-side geographic targeting; Query v1.0 has no viewer-location input.

](https://docs.aon.pro/api/location-search)[

Category Taxonomy

Browse the category ids accepted by constraints.category\_ids.

](https://docs.aon.pro/protocol/category-taxonomy)[

Errors & Rate Limits

Shared HTTP status, body envelope, and retry guidance.

](https://docs.aon.pro/api/errors-rate-limits)
