Python
Obstruo exposes an OpenAI-compatible API, so any Python library that talks to OpenAI works with Obstruo out of the box. This page covers the official openai SDK and raw httpx.
Prerequisites
- An ObstruoKey and endpoint URL - see Quick Start
- A Logical Model configured in your project
openai-python SDK
Install the SDK if you haven't already:
Replace your existing client instantiation:
import openai
client = openai.OpenAI(
api_key="your-obstruo-key",
base_url="https://api.obstruo.ai/your-org/v1",
)
Everything else stays the same - completions, streaming, embeddings, tool calls:
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}
]
response = client.chat.completions.create(
model="obstruo-chat",
messages=[{"role": "user", "content": "What's the weather in Warsaw?"}],
tools=tools,
)
Async client
Use AsyncOpenAI for async code - the interface is identical:
import asyncio
import openai
client = openai.AsyncOpenAI(
api_key="your-obstruo-key",
base_url="https://api.obstruo.ai/your-org/v1",
)
async def main():
response = await client.chat.completions.create(
model="obstruo-chat",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
asyncio.run(main())
Environment variables
Store credentials in environment variables rather than hardcoding them:
export OBSTRUO_API_KEY="your-obstruo-key"
export OBSTRUO_BASE_URL="https://api.obstruo.ai/your-org/v1"
import os
import openai
client = openai.OpenAI(
api_key=os.environ["OBSTRUO_API_KEY"],
base_url=os.environ["OBSTRUO_BASE_URL"],
)
Reading gateway metadata
Obstruo attaches metadata to every response. The location differs between streaming and non-streaming.
Non-streaming
The obstruo key is present in the response body:
response = client.chat.completions.create(
model="obstruo-chat",
messages=[{"role": "user", "content": "Hello!"}],
)
# standard OpenAI field
print(response.choices[0].message.content)
# redaction summary
redaction = response.model_extra.get("obstruo", {}).get("redaction", {})
print(redaction.get("total_entities")) # 0 = no PII found
print(redaction.get("by_category")) # {"EMAIL_ADDRESS": 1, ...}
# routing info
routing = response.model_extra.get("obstruo", {}).get("routing", {})
print(routing.get("resolved_model")) # "gpt-4o-mini"
print(routing.get("provider_type")) # "OpenAI"
Streaming
For streaming responses, metadata is available in the HTTP response headers:
stream = client.chat.completions.create(
model="obstruo-chat",
messages=[{"role": "user", "content": "Hello!"}],
stream=True,
)
pii_state = stream.response.headers.get("x-obstruo-pii-state")
# "no-pii" | "redacted" | "disabled"
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
Raw HTTP with httpx
If you prefer to call the API directly without the SDK:
import httpx
client = httpx.Client(
base_url="https://api.obstruo.ai/your-org/v1",
headers={"Authorization": "Bearer your-obstruo-key"},
)
response = client.post("/chat/completions", json={
"model": "obstruo-chat",
"messages": [{"role": "user", "content": "Hello!"}],
})
response.raise_for_status()
print(response.json()["choices"][0]["message"]["content"])