Skip to content
ABTO Guide

Integration guide

Python

A Python server SDK that routes provider requests through ABTO Gateway and carries user and feature context.

Server SDKRuns on your backend (Calling Key)

The Python SDK automatically carries the call-time user and feature context on gateway requests. Tokens, cost, latency, and the request identifier are recorded by the gateway.

import os
from abto import init_abto
abto = init_abto(
api_key=os.environ["ABTO_CALLING_KEY"],
gateway_base_url="https://gateway.abto.app/v1",
provider_keys={
"openai": os.environ["OPENAI_API_KEY"],
# Pass candidate keys together when the project routes across providers.
"anthropic": os.environ["ANTHROPIC_API_KEY"],
"gemini": os.environ["GEMINI_API_KEY"],
},
)
openai = abto.openai()
with abto.with_context(
device_id="device-abc",
feature_id="review.summary",
):
response = openai.chat.completions.with_raw_response.create(
model="gpt-4.1-mini",
messages=[{"role": "user", "content": "Summarize these 12 product reviews in three lines."}],
)
request_id = response.headers.get("x-abto-request-id")
completion = response.parse()
  • completion: the usual OpenAI response body
  • raw response: where you read the x-abto-request-id the Gateway issued
  • gateway_base_url: required. Omit it and the SDK reads ABTO_GATEWAY_BASE_URL; with neither it raises ValueError
SDK inputGateway headerMeaning
api_keyAuthorization: Bearer …ABTO Calling Key
provider_keys["openai"]x-abto-key-openaiYour own OpenAI provider key
provider_keys["gemini"]x-abto-key-geminiYour own Gemini provider key
provider_keys["anthropic"]x-abto-key-anthropicYour own Anthropic provider key
feature_idx-abto-feature-idFeature ID
device_idx-abto-device-idEnd-user device identifier (optional)

How provider_keys behaves:

  • Not a setting that registers keys with the Gateway. It is the input that attaches server-held credentials as per-request headers.
  • Passed with request scope only and never stored in call records.
  • If the routed provider has no key, the Gateway rejects that request.
  • Pass a callable instead of a string to re-evaluate it on every request. for key rotation and per-provider credential resolvers.

How caller-supplied headers are handled:

  • Do not override x-abto-key-* through extra_headers on a client built by abto.openai().
  • The Python SDK strips the caller’s Authorization, x-abto-key-*, x-abto-feature-id, and x-abto-device-id, then rebuilds them from the trusted init_abto settings and context.
  • Using the official OpenAI SDK directly instead? Put the same headers in each request’s extra_headers. see the direct OpenAI SDK example.

The fields mean the same as in Node / Server JavaScript.

  • feature_id: feature ID (e.g. review.summary), sent as x-abto-feature-id
  • device_id: sent as x-abto-device-id. Take the browser-generated device_id from your backend request and pass it through so product behavior joins.

Rules for handling identifiers:

  • Validate client-supplied device_id and feature_id with your application’s existing request schema.
  • Never accept the Calling Key or provider keys from client requests. Read them only from server environment variables or a server-only credential resolver.

Joining responses to browser and mobile behavior:

  • Read x-abto-request-id with with_raw_response as shown above.
  • Include the same header in your backend response to join the Browser or Mobile SDK LLM trace.
  • The data path is currently OpenAI Chat Completions.
  • Inline base64 images and PDFs in user messages are supported.
  • Function tool calling is supported. When you send tool results back, echo each message.tool_calls[].id as tool_call_id (not the top-level response id).
  • Unsupported fields such as streaming, remote image URLs, and audio are rejected with 400 rather than silently ignored.
  • See Gateway OpenAI compatibility for the exact field list.
openai = abto.openai(max_retries=2)
  • The official OpenAI SDK’s max_retries applies as written. ABTO never overwrites it.
  • Leave it unset and the official OpenAI SDK default applies.
  • The Calling SDK adds no retry count of its own.
  • Direct fallback exposes no count either, only the resend switch fallback.on_timeout, which is off by default.
  • Every other official OpenAI option is forwarded unchanged.
  • api_key, base_url, and http_client are owned by ABTO for trusted routing. passing them raises ValueError rather than being silently ignored.

OpenAI direct fallback on Gateway failures

Section titled “OpenAI direct fallback on Gateway failures”

This is the escape hatch back to the endpoint this application used before ABTO. Name that destination in fallback.base_url; there is no default. If you took an API key straight from OpenAI and used the official SDK, that address is https://api.openai.com/v1.

from abto import OpenAIDirectFallbackOptions, init_abto
abto = init_abto(
api_key=os.environ["ABTO_CALLING_KEY"],
gateway_base_url="https://gateway.abto.app/v1",
provider_keys={"openai": os.environ["OPENAI_API_KEY"]},
fallback=OpenAIDirectFallbackOptions(
# The address this code called before ABTO was put in front of it.
base_url="https://api.openai.com/v1",
timeout_seconds=30,
on_timeout=False,
),
)

The original Chat Completions body and model go straight to that address; the Gateway’s provider/model policy is not reproduced.

Sends the current request directly

  • The request never reached ABTO
  • It reached ABTO but was rejected before the provider was called

In other words, it switches only when the provider certainly did not run, so it never creates a double execution or a double charge.

Does not fall back the current request

  • Timeouts and disconnects with ambiguous delivery. the Gateway may already have run the provider
  • Provider, transport, and internal errors; deterministic 4xx and 429; anything after streaming has started
  • The direct circuit stays closed in these cases, and if the official OpenAI SDK retries it calls the Gateway again

Settings

  • base_url: required. The OpenAI-compatible endpoint used before ABTO. It must accept the OpenAI request path and Authorization: Bearer.
    • Naming this destination is how fallback is turned on. There is no separate enable flag.
    • init_abto raises ValueError for fallback=True with no destination, and for a destination with no OpenAI key.
  • timeout_seconds: per-stage inactivity cap for Gateway connection pool wait, connect, write, and response header read. The body after headers and direct requests keep the abto.openai(timeout=...) value.
  • on_timeout=True: also resends the timed-out request. An explicit choice that accepts duplicate execution and billing risk.
  • fallback=False: turns the whole feature off.

Boundaries

  • Per SDK attempt the transport makes the Gateway judgment and the direct send exactly once each.
  • Direct calls bypass Gateway policy, ABTO telemetry, and request_id, and must use a model that endpoint supports.
  • Only headers OpenAI needs are forwarded; cookies, proxy credentials, and custom Gateway headers are stripped.
  • After switching to direct, OpenAI responses and errors are returned to the official OpenAI SDK unchanged, and that SDK decides whether to retry.
  • Native direct fallback for Anthropic and Gemini is out of scope today.