API Reference · Discover
Offers for Contents API
Get relevant offers for web pages, inline text, images, and video with a live Content Assistant placement.
Base URL: https://api.aon.pro · Content API 1.2.0
Authentication
Send X-AON-Placement-Id with the public ID of a live Content Assistant placement from Developer Portal on every request. No API key is required. Anonymous requests and other placement types are not supported. Use https://api.aon.pro or https://plugin.aon.pro, not the documentation site.
Submit content and get offers
- Send a web URL, inline text, or an image/video HTTPS URL to
POST /v1/content/offers. Setsource.typetoweb,inline,imageorvideo. Setlanguageexplicitly; otherwiseAccept-Languageis used, thenen. - HTTP
202withdata.status=pending: waitdata.poll_after_ms, then repeat the same POST with unchanged content and language and current viewer context. No task ID, resource ID orLocationis needed or returned. - HTTP
200withdata.status=ready: readdata.matches. Each match contains anintent, itsoffersand a nullable videosegment. Empty matches or offers are valid results.
Using offers
Video segments use start_ms and end_ms; repeated appearances have separate matches. For other content, or video without known segments, segment is null. Keep each returned offer_instance_id and the entire action together and unchanged.
For server-side calls, supply the viewer's context.user_profile.country and, when available, client.user_agent so matching uses the viewer's context rather than your server's.
Errors and retries
Errors return data:null. For CONTENT_ANALYSIS_FAILED, inspect extra.reason, extra.retryable and extra.retry_at before resubmitting. For HTTP 429, honor Retry-After or extra.retry_after_seconds and use backoff. These are separate from pending-response polling. Keep X-Request-Id for support.
Operations
/v1/content/offersPlacement IDX-AON-Placement-IdstringSend the public ID of a live Content Assistant placement in X-AON-Placement-Id exactly once on every request. Use 1–64 ASCII letters, digits, underscores or hyphens. A placement_id in the body or query is not used. API keys, anonymous requests and other placement types are not supported.
example: plc_YOUR_PLACEMENT_IDContent-TypestringJSON request body.
example: application/jsonAccept-LanguagestringPreferred output language when language is omitted; defaults to en.
x-aon-user-pseudo-idstringOptional pseudonymous viewer ID; not echoed in the response.
x-aon-consentstringOptional viewer consent: personalization=granted|denied;jurisdiction=<code>;age=<value>.
JSON body. Maximum 2097152 bytes. Omit: force_refresh, resource_id, task_id, pagination.
sourceobjectExactly one of the source shapes below; never mix their fields.
languagestringDesired result language. Send it explicitly and keep it unchanged when repeating a pending request.
objectCurrent viewer and session context for offer matching.
5 nested fieldsobjectApplication information.
3 nested fieldsnamestringApplication name.
minLength: 1versionstringApplication version.
minLength: 1channelstringApplication channel.
minLength: 1session_idstringPseudonymous session identifier.
minLength: 1maxLength: 256conversation_idstring | numberConversation identifier.
objectRecent session context.
2 nested fieldsprevious_request_idstringPrevious AON request ID.
format: uuidrecent_topicsstring[]Up to ten recent conversation topics. Maximum items: 10.
items: stringobjectCurrent viewer targeting information.
3 nested fieldscountrystringUppercase ISO country code, such as US. Supply the viewer's country for server-side calls; otherwise country inference may use your server's region. Resolvable location_ids take precedence.
pattern: ^[A-Z]{2}$location_idsstring[]Canonical AON location IDs for the viewer. Minimum items: 1. Maximum items: 10.
items: stringverified_age_overintegerVerified minimum age threshold, not an inferred or exact age.
minimum: 13maximum: 120objectCurrent viewer client information. Omit properties: ip.
1 nested fielduser_agentstringViewer user agent. If omitted, the request's User-Agent header is used. No client IP field is supported. Maximum UTF-8 bytes: 2048.
minLength: 1objectOptional filters for the returned offers.
4 nested fieldscategory_idsstring[]Include these category IDs.
items: stringexcluded_category_idsstring[]Exclude these category IDs.
items: stringoffer_typesstring[]Allowed offer types.
items: stringlisting_source_namesstring[]Allowed listing sources.
items: stringforce_offerbooleanRequest a fallback recommendation when normal matching finds none.
objectOptions for the returned offers.
1 nested fieldthinking_modebooleanWhether offers include match reasons. If omitted, the service default applies.
Fields for source.type = web. Omit: contents, media_type.
objectA publicly accessible HTTP or HTTPS web page. Omit properties: contents, media_type.
2 nested fieldstypestringContent type: web, inline, image or video.
Allowed valuesweburistringHTTP or HTTPS URL of the page, including any required query parameters. Maximum UTF-8 bytes: 8192.
Fields for source.type = inline. Omit: media_type.
objectPlain text supplied directly. The application URI identifies the text and is not fetched. Omit properties: media_type.
4 nested fieldstypestringContent type: web, inline, image or video.
Allowed valuesinlineuristringApplication URI, such as myapp://articles/123. This address is not fetched. Maximum UTF-8 bytes: 4096.
contentsobject[]Original text entries in order. At least one nonblank entry is required. Keep the text and entry boundaries unchanged when repeating a pending request. Minimum items: 1. Maximum items: 32. Maximum decoded UTF-8 bytes: 262144.
items: objectobjectNested object container for the fields below.
2 nested fieldstypestringText entry type; use text.
Allowed valuestexttextstringOriginal plain text, not HTML.
Fields for source.type = image. Omit: contents, media_type.
objectAn image or video at an HTTPS URL. Set source.type to image or video; do not send media_type. Omit properties: contents, media_type.
2 nested fieldstypestringContent type: web, inline, image or video.
Allowed valuesimageuristringHTTPS URL of the image or video. Do not include credentials, control characters or surrounding whitespace.
maxLength: 2000Fields for source.type = video. Omit: contents, media_type.
objectAn image or video at an HTTPS URL. Set source.type to image or video; do not send media_type. Omit properties: contents, media_type.
2 nested fieldstypestringContent type: web, inline, image or video.
Allowed valuesvideouristringHTTPS URL of the image or video. Do not include credentials, control characters or surrounding whitespace.
maxLength: 2000HTTP 200: ready matches. HTTP 202: pending; wait poll_after_ms and repeat POST with the same content and language. Error responses have data:null.
codestringResponse code. SUCCESS does not mean offers are ready; inspect data.status. Machine-readable error code.
Allowed valuesSUCCESSINVALID_JSONUNSUPPORTED_MEDIA_TYPEVALIDATION_ERRORPAYLOAD_TOO_LARGEPLACEMENT_REJECTEDRESULT_REVOKEDNOT_FOUNDAPI_NOT_FOUNDMETHOD_NOT_ALLOWEDRESULT_EXPIREDRATE_LIMITEDSERVICE_UNAVAILABLEINTERNAL_ERRORCONTENT_ANALYSIS_FAILEDOFFER_QUERY_TIMEOUTRESULT_TOO_LARGEmessagestringHuman-readable explanation. Use code and data.status for application logic.
object | nullReady matches or a pending status.
5 nested fieldsnullable: truestatusstringready when matching is complete. pending while the content is being prepared.
Allowed valuesreadypendingsource_typestringThe submitted source.type.
Allowed valueswebinlineimagevideomatchesobject[]Each entry pairs an intent and its offers with an optional video segment. Empty when no intents are found.
items: objectobjectNested object container for the fields below.
4 nested fieldsobject | nullVideo appearance interval, or null for web, inline text, images and videos without known segments. Repeated video appearances have separate matches.
2 nested fieldsnullable: truestart_msintegerStart of the appearance, in milliseconds.
minimum: 0maximum: 600000end_msintegerEnd of the appearance, in milliseconds.
minimum: 0maximum: 600000intentstringProduct or commercial intent identified in the content.
minLength: 1offersobject[]Up to twenty complete public Offer objects for this intent. An empty array means no offers are available. Offers are deduplicated within an intent, not across unrelated matches. Maximum items: 20.
items: objectobjectNested object container for the fields below.
7 nested fieldsoffer_idstringCanonical Offer ID.
format: uuidoffer_instance_idstringOpaque ID for this served Offer. Preserve unchanged.
format: uuidversionstringOffer schema version.
minLength: 1objectOffer details. Additional public fields may include pricing and creative assets.
3 nested fieldstitlestringOffer title.
minLength: 1descriptionstringOffer description.
minLength: 1objectOffer category.
1 nested fieldidstringCanonical category ID.
minLength: 1objectMerchant or service provider.
2 nested fieldsidstringEntity identifier.
minLength: 1namestringEntity display name.
minLength: 1objectOriginal action for this served Offer. Do not replace tracked links.
2 nested fieldstypestringAction type.
minLength: 1objectAction details.
1 nested fieldurlstringTracked HTTPS destination. Preserve this URL unchanged.
format: uripattern: ^https://content_languagestringLanguage of the Offer content.
poll_after_msinteger | nullMilliseconds to wait before repeating POST with the same content and language and current viewer context. Use each response's value.
nullable: trueminimum: 1objectAdditional response information.
4 nested fieldsretry_after_secondsintegerSeconds to wait before retrying a rate-limited request.
Allowed values60reasonstringReason the content could not be processed.
retryablebooleanWhether submitting again later may succeed.
retry_atstring | nullEarliest time to submit again, if provided. Not a pending-response polling interval.
format: date-timenullable: trueINVALID_JSON, UNSUPPORTED_MEDIA_TYPE or VALIDATION_ERROR: check the request. CONTENT_ANALYSIS_FAILED: the content could not be processed.
- Use application/json and check the documented fields. For CONTENT_ANALYSIS_FAILED, inspect extra.reason, retryable and retry_at before submitting again.
PLACEMENT_REJECTED: the placement is not permitted. RESULT_REVOKED: the result is no longer available.
- Use a live Content Assistant placement. Stop using a revoked result.
RESULT_EXPIRED or NOT_FOUND: no available result was found.
- Check the content source. Do not treat an expired result as a pending response.
METHOD_NOT_ALLOWED: this endpoint requires POST.
- Use POST and check the Allow response header.
PAYLOAD_TOO_LARGE: the request exceeds the allowed size.
- Keep the JSON body within 2 MiB and the combined decoded inline text within 256 KiB.
RATE_LIMITED: the request cannot be served yet.
- Wait for Retry-After or extra.retry_after_seconds, then retry with backoff and jitter. This is separate from pending-response polling.
CONTENT_ANALYSIS_FAILED, OFFER_QUERY_TIMEOUT, SERVICE_UNAVAILABLE, INTERNAL_ERROR or RESULT_TOO_LARGE: the request could not be completed.
- For CONTENT_ANALYSIS_FAILED, follow extra.retryable and retry_at. RESULT_TOO_LARGE means the response exceeds 2 MiB; it is not silently truncated. Otherwise retry with backoff if appropriate. Keep X-Request-Id for support.
Behavior, compatibility, and source notes
Submit content and current viewer context. HTTP 202 means pending: wait poll_after_ms and repeat this POST with the same source and language. HTTP 200 means ready, including empty matches or offers. Available matches may be returned even when some matching attempts fail; results do not promise exhaustive inventory or stable ranking. Keep each offer_instance_id and action unchanged. The response is limited to 2 MiB; oversized results return RESULT_TOO_LARGE, not truncated offers.
- HTTP 202: data.status is pending. Wait data.poll_after_ms, then repeat POST with the same content and language and current viewer context. No Location or task ID is returned.
Implementation checklist · 3 items
- Create a live Content Assistant placement in Developer Portal and send its X-AON-Placement-Id on every request; other placement types and anonymous requests are not supported.
- For HTTP 202, wait data.poll_after_ms, then repeat POST with the same content and language and current viewer context.
- Keep each returned offer_instance_id and action unchanged for attribution.