Skip to content
 

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

POST/v1/offers/queryBearer required
Search offers by intent
OpenAPI security
Headers

Headers that should be present on this request.

Fields
5·3 required/2 optional
Showing the complete documented schema.
Required or conditional
AON-Protocol-Versionstring
required

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

Authorizationheader
required

Bearer token for authenticated platform requests.

example: Bearer YOUR_API_KEY
Content-Typeheader
required

Request body format for JSON endpoints.

example: application/json
Optional
x-aon-user-pseudo-idstring
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-consentstring
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.

Fields
57·5 required/23 conditional/29 optional
Showing the complete documented schema.
Required or conditional
object
required

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

4 nested fields
object
optional

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

3 nested fieldsexample: { "name": "shopping-bot", "channel": "api" }
object
optional

Bounded session continuity for the current conversation.

2 nested fieldsexample: { "previous_request_id": "019dd200-1234-7890-abcd-ef0123456788" }
session_idstring
optional

Optional session identifier for support correlation.

example: sess_123maxLength: 256
conversation_idstring | number
optional

Optional host conversation identifier.

example: conversation_123
object
required

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

6 nested fields
object
optional

Explicit opt-in Flight search constraints.

2 nested fields
object[]
required

Exactly one current text or image input item.

3 nested fieldsexample: { "type": "input_text", "text": "noise cancelling headphones under $200" }
typestring
required

Content item kind. Most server integrations start with `input_text`.

example: input_textAllowed valuesinput_textinput_image
textstring
required when intent.content[].type is input_text

Free-text user intent when the item type is `input_text`.

example: noise cancelling headphones under $200minLength: 1maxLength: 200
image_urlstring
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.jpgformat: uri
provenancestring
required

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

example: user_expressedAllowed valuesuser_expressedinferred_context
confidencenumber
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.8minimum: 0maximum: 1
object[]
optional

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

2 nested fields
object
optional

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

3 nested fields
Optional
request_idstring
optional

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

example: 019dd200-1234-7890-abcd-ef0123456789format: uuid
timestampstring
optional

Optional RFC 3339 timestamp for when the request was created.

example: 2026-04-28T03:30:00Zformat: date-time
test_modeboolean
optional

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

example: false
placement_idstring
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_A1b2C3d4E5f6G7h8minLength: 1maxLength: 64pattern: ^\S+$
object
optional

Explicit public taxonomy constraints for the current Query.

2 nested fields
category_ids[]string[]
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
excluded_category_ids[]string[]
optional

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

example: arts_entertainment.adult_entertainment
force_offerboolean
optional

Request a fallback recommendation when normal matching returns no offer.

example: false
object
optional

Optional controls for the shape of the current Query response.

1 nested field
thinking_modeboolean
optional

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

example: true
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.