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-idthe Gateway issued gateway_base_url: required. Omit it and the SDK readsABTO_GATEWAY_BASE_URL; with neither it raisesValueError
Gateway headers sent on every request
Section titled “Gateway headers sent on every request”| SDK input | Gateway header | Meaning |
|---|---|---|
api_key | Authorization: Bearer … | ABTO Calling Key |
provider_keys["openai"] | x-abto-key-openai | Your own OpenAI provider key |
feature_id | x-abto-feature-id | Feature ID |
device_id | x-abto-device-id | End-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-*throughextra_headerson a client built byabto.openai(). - The Python SDK strips the caller’s
Authorization,x-abto-key-*,x-abto-feature-id, andx-abto-device-id, then rebuilds them from the trustedinit_abtosettings 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.
Context fields
Section titled “Context fields”The fields mean the same as in Node / Server JavaScript.
feature_id: feature ID (e.g.review.summary), sent asx-abto-feature-iddevice_id: sent asx-abto-device-id. Take the browser-generateddevice_idfrom your backend request and pass it through so product behavior joins.
Rules for handling identifiers:
- Validate client-supplied
device_idandfeature_idwith 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-idwithwith_raw_responseas shown above. - Include the same header in your backend response to join the Browser or Mobile SDK LLM trace.
OpenAI requests the Gateway supports
Section titled “OpenAI requests the Gateway supports”- The data path is currently OpenAI Chat Completions.
- Inline base64 images and PDFs in
usermessages are supported. - Unsupported fields such as streaming, tool calling, remote image URLs, and audio are rejected with
400rather than silently ignored. - See Gateway OpenAI compatibility for the exact field list.
Retries happen at two layers
Section titled “Retries happen at two layers”Because there are two layers, max_retries alone does not determine how many times a provider is called.
| Layer | What it counts | Who decides |
|---|---|---|
| Client | Application → Gateway round trips | The official OpenAI SDK’s max_retries |
| Gateway | Gateway → provider invocations | Gateway built-in caps and the node retry policy |
Client layer: max_retries
Section titled “Client layer: max_retries”openai = abto.openai(max_retries=2)- Keeps the official OpenAI meaning: retries after the initial request.
0is one round trip,1is two. - The Python SDK never overwrites it and offers no separate fallback retry count.
- Leave it unset and the official OpenAI SDK default applies.
- Every other official OpenAI option is forwarded unchanged.
api_key,base_url, andhttp_clientare owned by ABTO for trusted routing. passing them raisesValueErrorrather than being silently ignored.
Gateway layer: retries inside a single round trip
Section titled “Gateway layer: retries inside a single round trip”Within one round trip the Gateway may re-attempt along the same path.
- Network retries: only when non-delivery is certain (unreachable). Always on, regardless of node policy, up to 2.
- Provider retries:
429(rate limit),500,502,503,504,529. Only when the node retry policy is enabled, up to 2. - The two budgets add independently, so one round trip can invoke the provider up to 5 times (1 initial + 2 network + 2 provider).
- The
x-abto-attemptresponse header reports which attempt produced the response.
Never retried:
429with credit exhaustion (insufficient_quota). a deterministic failure- Timeouts, post-send disconnects, body size overruns, and cancellation. risk of double execution and double billing
- Other deterministic statuses such as
501and505
Wait times:
- Exponential backoff with full jitter. Network: 50ms base, 250ms cap. Provider: 500ms base, 8s cap.
- A provider-supplied
Retry-Afteris honored as given; beyond the 8s cap the Gateway does not wait and surfaces the error immediately.
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
- Failures before the connection is established
- Admission
503raised before the provider call
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
4xxand429; 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 andAuthorization: Bearer. Enabling fallback without it makesinit_abtoraiseValueError.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 theabto.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.