Skip to content
 

Python SDK Reference

Signature-first reference for agentoffernetwork.

Protocol default

The live client sends the exact current selector AON-Protocol-Version: 1.0. Returned Offers follow the canonical Protocol v1.0 schema and generated SDK types.

Package

Install with pip install agentoffernetwork or uv add agentoffernetwork. Current documented version: v1.0.0

Pinned docs baseline

This reference targets the current repository baseline: Python 3.11+ and agentoffernetwork v1.0.0.

Use live mode only with an issued Live Key owned by a serviceable Application. Installation, package imports, and a local mock do not establish this access condition.

Primary Exports

from agentoffernetwork import (
    initialize,
    create_context_for_platform,
    detect_context,
    format_recommendation,
    AON_CURRENT_PROTOCOL_VERSION,
    AON_PROTOCOL_VERSION_V10,
    AgentOfferClient,
    MockAgentOfferClient,
    SDKConfig,
    QueryOffersParams,
    QueryContext,
    QuerySession,
    QueryPlatform,
    Intent,
    TextContentPart,
    QueryConstraints,
    QueryOffersResponse,
    ClickEvent,
    ConversionEvent,
    FormatOptions,
)

initialize(config)

Creates a live or mock client after validating configuration.

initialize(config)
Python
client = await initialize(SDKConfig(
    api_key="your-token",
    mode="live",
    base_url="https://api.aon.pro",
    timeout=5000,
))
Parameter
api_key
strRequired

Bearer token used for live API requests. Must be non-empty.

mode
Literal["mock", "live"]Required

mock returns local sample data; live uses the HTTP API.

base_url
strOptional

Overrides the default live API origin. Defaults to https://api.aon.pro.

timeout
float | NoneOptional

Timeout value accepted by the SDK config. Current live implementation interprets 5000 as a five second timeout.

Validation behavior:

  • Empty api_key raises AonValidationError.
  • Any mode other than mock or live raises AonValidationError.
  • timeout <= 0 raises AonValidationError.

AgentOfferClient Protocol

class AgentOfferClient(Protocol):
    async def query_offers(self, params: QueryOffersParams) -> QueryOffersResponse: ...
    async def report_click(self, event: ClickEvent) -> ClickResult: ...
    def format_recommendation(self, offer: Offer, options: FormatOptions | None = None) -> str: ...

All network-calling methods are async. format_recommendation is synchronous.

query_offers(params)

query_offers serializes dataclass fields to protocol snake_case and sends POST /v1/offers/query in live mode.

response = await client.query_offers(QueryOffersParams(
    request_id="req-123",
    context=QueryContext(
        platform=QueryPlatform(name="shopping-bot", channel="api"),
        session=QuerySession(recent_topics=["audio"]),
    ),
    intent=Intent(content=[
        TextContentPart(type="input_text", text="noise cancelling headphones under $200"),
    ], provenance="user_expressed", signals={"budget": {"max": 200, "currency": "USD"}}),
    constraints=QueryConstraints(
        category_ids=["computers_electronics.consumer_electronics"],
    ),
    force_offer=True,
    response_options={"thinking_mode": True},
))
Parameter
request_id
str | NoneOptional

Optional caller-supplied request identifier.

timestamp
str | NoneOptional

Optional RFC 3339 timestamp.

test_mode
bool | NoneOptional

Marks the request as test traffic.

context
QueryContextRequired

Bounded platform, session, session_id, and conversation_id context. Long-term profiles are not sent on the Protocol v1.0 wire.

intent.content
list[ContentPart]Required

At least one content part. Supported variants are input_text and input_image.

intent.provenance
user_expressed | inferred_contextOptional

Defaults to user_expressed. Inferred intent requires a bounded confidence value.

constraints
QueryConstraints | NoneOptional

category_ids and excluded_category_ids.

force_offer
bool | NoneOptional

Permits a qualified fallback Offer when an exact match is unavailable.

response_options.thinking_mode
bool | NoneOptional

Defaults to true. Set false to omit offer match_reason values.

QueryOffersResponse shape:

QueryOffersResponse(
    request_id=str,
    offers=list[Offer],
    query_id=str | None,  # deprecated legacy alias for request_id
    total=int | None,     # SDK-derived convenience, not a protocol response field
    has_more=bool | None, # SDK-derived convenience, not a protocol response field
)

Important notes:

  • validate_content() runs before the HTTP request.
  • request_id maps to protocol data.request_id. query_id is a deprecated legacy alias when present.
  • The SDK selects Protocol 1.0 and validates returned Offers against the current contract.
  • total and has_more are SDK-derived conveniences, not protocol/OpenAPI response fields.
  • The SDK exposes protocol offer_id as offer.offer_id and offer_instance_id as offer.offer_instance_id.
  • tracking_url is the AON tracking endpoint supplied by your integration layer for the selected offer.

report_click(event)

report_click performs a GET against the offer's tracking URL and extracts the tracking identifier from that URL.

click = await client.report_click(ClickEvent(
    offer_id=offer.offer_id,
    tracking_url="https://tracking.example.test/click/mock-track-1",
    timestamp="2026-04-16T12:00:00Z",
    agent_id="shopping-bot",
    session_id="session-123",
    context={"conversation_id": "conv-456"},
))
 
print(click.tracking_id)
print(click.timestamp)
Parameter
offer_id
strRequired

Offer identifier from query results.

tracking_url
strRequired

AON tracking URL supplied by your integration layer for the selected offer. Do not synthesize it from offer_id.

timestamp
strRequired

Client-side event timestamp.

agent_id
str | NoneOptional

Optional identifier for the calling agent.

session_id
str | NoneOptional

Optional session key for deduplication and analytics.

context
dict[str, Any] | NoneOptional

Optional structured metadata.

format_recommendation(offer, options=None)

Formats an Offer into display-ready text. The standalone function and the client method share the same implementation.

text = client.format_recommendation(offer, FormatOptions(
    style="markdown",
    include_disclosure=True,
    disclosure_text="Sponsored",
    include_price=True,
))
Parameter
style
Literal["brief", "detailed", "markdown"]Optional

Output style. Defaults to markdown.

include_disclosure
boolOptional

Whether to append the disclosure label. Defaults to true.

disclosure_text
strOptional

Disclosure label text. Defaults to Sponsored.

include_price
boolOptional

Whether to include price if the offer contains one. Defaults to true.

detect_context(...)

detect_context() builds a QueryContext with platform, language, and session defaults.

context = detect_context(
    platform_name="custom-agent",
    channel="api",
    user_pseudo_id="anon-42",
    interests=["travel", "credit cards"],
)

Auto-detection behavior:

  • Non-TTY processes default to mcp-skill / mcp.
  • Other runtimes default to sdk / api.
  • LANG, LC_ALL, or LC_MESSAGES drive language detection.
  • A session identifier is generated once per process.

create_context_for_platform(target, ...)

Use the explicit platform adapter when the host platform is already known.

from agentoffernetwork import create_context_for_platform, CustomPlatformTarget
 
mcp_context = create_context_for_platform(
  "mcp-skill",
  interests=["Apple ecosystem user"],
)
 
coze_context = create_context_for_platform(
  "coze",
  native_user_id="user-123",
  native_session_id="conv-1",
)
 
custom_context = create_context_for_platform(
  CustomPlatformTarget(name="partner-builder", channel="agent"),
)

Built-in targets:

  • sdk → platform.name = sdk, platform.channel = api
  • mcp-skill → platform.name = mcp-skill, platform.channel = mcp
  • chatgpt → platform.name = chatgpt, platform.channel = action
  • coze → platform.name = coze, platform.channel = plugin, native user IDs normalize to coze:<id>
  • dify → platform.name = dify, platform.channel = tool, native user IDs normalize to dify:<id>

Notes:

  • Explicit platform_name, channel, session_id, and user_pseudo_id overrides always win.
  • Empty native user IDs do not produce guessed user_pseudo_id values.
  • ChatGPT Action integrations should still omit platform and user_pseudo_id in the request body; the F011 server path injects them automatically.

Mock Testing

Mock mode records click and conversion events in memory.

mock = await initialize(SDKConfig(api_key="test-key", mode="mock"))
 
await mock.report_click(ClickEvent(
    offer_id="offer-1",
    tracking_url="https://example.com/track/mock-track-1",
    timestamp="2026-04-16T12:00:00Z",
))
 
print(mock.get_recorded_events())

Error Classes

ClassCodeWhen it is raised
AonValidationErrorVALIDATION_ERRORInvalid SDK configuration or invalid query content
AonAuthErrorAUTH_ERROR401 responses or failed authentication
AonRateLimitErrorRATE_LIMIT429 responses
AonNetworkErrorNETWORK_ERRORTimeout, transport, or non-JSON transport failures
AonApiErrorserver-providedAPI returned a business error code instead of SUCCESS

Python live completion

The Python path is complete only when query_offers with your issued Live Key returns a canonical v1.0 result. Empty offers or data.empty_reason are valid results. A local mock, authentication failure, or protocol failure is not live completion.

Review Production Access & API Keys

Review Authentication