Environment
This example uses urllib.request, json, and os; no SDK is required. Set the Gateway key outside the source file. It calls the free sandbox-chat model. The fixed idempotency key is for one sample request; generate a new opaque ID per real logical job.
A complete request
import json
import os
import urllib.request
import urllib.error
base_url = os.environ.get("GATEWAY_BASE_URL", "https://gateway.accountablehq.com")
api_key = os.environ["GATEWAY_API_KEY"]
payload = {
"model": "sandbox-chat",
"messages": [{"role": "user", "content": "Explain an AI gateway in one sentence."}],
"max_tokens": 64,
}
request = urllib.request.Request(
f"{base_url}/v1/chat/completions",
data=json.dumps(payload).encode("utf-8"),
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"Idempotency-Key": "python-001",
},
method="POST",
)
try:
with urllib.request.urlopen(request, timeout=620) as response:
result = json.load(response)
except urllib.error.HTTPError as error:
result = json.load(error)
raise RuntimeError(f"{error.code}: {result.get('error', {}).get('code')}") from None
print(result["choices"][0]["message"]["content"])
print({"request_id": result["id"], "usage": result["usage"], "cost": result["gateway"]["charged_usd"]})With the official OpenAI SDK
import os
import uuid
from openai import OpenAI
client = OpenAI(
base_url="https://gateway.accountablehq.com/v1",
api_key=os.environ["GATEWAY_API_KEY"],
max_retries=0, # retry deliberately with an Idempotency-Key instead
)
completion = client.chat.completions.create(
model="sandbox-chat", # later: a production alias such as "gpt-6-luna"
messages=[{"role": "user", "content": "Explain an AI gateway in one sentence."}],
max_tokens=64,
extra_headers={"Idempotency-Key": str(uuid.uuid4())},
)
print(completion.choices[0].message.content)Automatic SDK retries are turned off on purpose. A timeout does not prove the model did not run, so a blind retry can be billed twice. Retry only with the same Idempotency-Key; the gateway refuses a duplicate while the first attempt is pending or succeeded, and accepts the same key again after a failure that cost nothing. See idempotency.
Handle network failures separately
HTTPError contains a structured gateway error. A network error or timeout might arrive without any HTTP response; the provider may still have executed. Preserve the logical request ID and reconcile instead of blindly submitting a new generation.
The timeout is a client waiting limit, not provider cancellation. Do not automatically print response content in production logs; this example prints a fictional answer to make the local test easy to inspect.
Next steps
Read responses and usage for parsing fields and credits and reservations for accounting. Use a model returned by your key’s catalog when you move from a sandbox key to a production key.