Python SDK
SandBase doesn't require a custom SDK. Use the official openai and anthropic Python packages you already know — just point them at SandBase.
# That's it. Change the base_url, use your SandBase API key.
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)This gives you access to 1400+ models from 50+ providers through a single endpoint, with smart routing, auto-fallback, and unified billing.
How It Works
SandBase implements the OpenAI and Anthropic APIs. Any code that works with those SDKs works with SandBase — you only change two things:
| Setting | OpenAI Direct | SandBase |
|---|---|---|
base_url | https://api.openai.com/v1 (default) | https://api.sandbase.ai/v1 |
api_key | sk-... (OpenAI key) | sk-sb-... (SandBase key) |
The same applies to the Anthropic SDK:
| Setting | Anthropic Direct | SandBase |
|---|---|---|
base_url | https://api.anthropic.com (default) | https://api.sandbase.ai |
api_key | sk-ant-... (Anthropic key) | sk-sb-... (SandBase key) |
Installation
pip install openaipip install anthropicpip install openai anthropicConfiguration
OpenAI SDK
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)Anthropic SDK
import anthropic
client = anthropic.Anthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key"
)Environment Variables
The cleanest approach — no credentials in code:
# .env or shell environment
export OPENAI_BASE_URL="https://api.sandbase.ai/v1"
export OPENAI_API_KEY="sk-sb-your-key"from openai import OpenAI
# Reads OPENAI_BASE_URL and OPENAI_API_KEY automatically
client = OpenAI()For the Anthropic SDK:
export ANTHROPIC_BASE_URL="https://api.sandbase.ai"
export ANTHROPIC_API_KEY="sk-sb-your-key"import anthropic
# Reads ANTHROPIC_BASE_URL and ANTHROPIC_API_KEY automatically
client = anthropic.Anthropic()TIP
Use a .env file with python-dotenv for local development. Never commit API keys to version control.
Chat Completions
Basic Request
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
]
)
print(response.choices[0].message.content)
# "The capital of France is Paris."import anthropic
client = anthropic.Anthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key"
)
response = client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
system="You are a helpful assistant.",
messages=[
{"role": "user", "content": "What is the capital of France?"}
]
)
print(response.content[0].text)
# "The capital of France is Paris."Multi-Turn Conversation
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
messages = [
{"role": "system", "content": "You are a math tutor."},
{"role": "user", "content": "What is 2 + 2?"},
]
response = client.chat.completions.create(model="gpt-4o", messages=messages)
assistant_msg = response.choices[0].message
messages.append({"role": "assistant", "content": assistant_msg.content})
# Continue the conversation
messages.append({"role": "user", "content": "Now multiply that by 3"})
response = client.chat.completions.create(model="gpt-4o", messages=messages)
print(response.choices[0].message.content)
# "4 × 3 = 12"Switching Models
One of SandBase's strengths — switch between any provider's models without changing your code:
# Use OpenAI
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}]
)
# Use Google
response = client.chat.completions.create(
model="gemini-2.5-pro",
messages=[{"role": "user", "content": "Hello"}]
)
# Use Meta
response = client.chat.completions.create(
model="llama-4-maverick",
messages=[{"role": "user", "content": "Hello"}]
)Streaming
OpenAI SDK Streaming
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
stream = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Write a haiku about coding"}],
stream=True
)
for chunk in stream:
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
print() # Newline at endAnthropic SDK Streaming
import anthropic
client = anthropic.Anthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key"
)
with client.messages.stream(
model="claude-sonnet-4",
max_tokens=1024,
messages=[{"role": "user", "content": "Write a haiku about coding"}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()Async Streaming
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
async def stream_response():
stream = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Tell me a story"}],
stream=True
)
async for chunk in stream:
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
asyncio.run(stream_response())Function Calling (Tools)
OpenAI SDK Tools
import json
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, e.g. 'Tokyo'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
tools=tools
)
# Check if the model wants to call a tool
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
print(f"Function: {tool_call.function.name}")
print(f"Arguments: {args}")
# {"location": "Tokyo", "unit": "celsius"}
# Execute the function and send the result back
messages = [
{"role": "user", "content": "What's the weather in Tokyo?"},
message, # Assistant's tool call
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps({"temperature": 22, "condition": "sunny"})
}
]
final_response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools
)
print(final_response.choices[0].message.content)Anthropic SDK Tools
import anthropic
client = anthropic.Anthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key"
)
response = client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather for a location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, e.g. 'Tokyo'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
],
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}]
)
# Process tool use
for block in response.content:
if block.type == "tool_use":
print(f"Tool: {block.name}")
print(f"Input: {block.input}")
# {"location": "Tokyo", "unit": "celsius"}Vision (Image Input)
URL Image
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/photo.jpg"
}
}
]
}
]
)
print(response.choices[0].message.content)Base64 Image
import base64
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
with open("image.png", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image_data}"
}
}
]
}
]
)Anthropic SDK Vision
import anthropic
import base64
client = anthropic.Anthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key"
)
with open("image.png", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_data
}
},
{"type": "text", "text": "Describe this image"}
]
}
]
)
print(response.content[0].text)Structured Output (JSON Mode)
JSON Schema
import json
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "Extract structured data from the text."},
{"role": "user", "content": "John is 30 years old and lives in New York."}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "person_info",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"city": {"type": "string"}
},
"required": ["name", "age", "city"]
}
}
}
)
data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "John", "age": 30, "city": "New York"}Pydantic with Structured Outputs
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
class PersonInfo(BaseModel):
name: str
age: int
city: str
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[
{"role": "system", "content": "Extract structured data from the text."},
{"role": "user", "content": "John is 30 years old and lives in New York."}
],
response_format=PersonInfo
)
person = response.choices[0].message.parsed
print(f"{person.name}, {person.age}, {person.city}")
# "John, 30, New York"Error Handling
OpenAI SDK Errors
from openai import (
OpenAI,
APIConnectionError,
RateLimitError,
APIStatusError,
)
client = OpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key",
max_retries=3, # Automatic retry with exponential backoff
timeout=30.0, # Request timeout in seconds
)
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}]
)
except APIConnectionError:
print("Failed to connect to SandBase. Check your network.")
except RateLimitError:
print("Rate limited. The SDK will retry automatically.")
except APIStatusError as e:
print(f"API error {e.status_code}: {e.message}")Anthropic SDK Errors
import anthropic
client = anthropic.Anthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key",
max_retries=3,
timeout=30.0,
)
try:
response = client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
except anthropic.APIConnectionError:
print("Failed to connect to SandBase. Check your network.")
except anthropic.RateLimitError:
print("Rate limited. The SDK will retry automatically.")
except anthropic.APIStatusError as e:
print(f"API error {e.status_code}: {e.message}")Common Error Codes
| Code | Meaning | Action |
|---|---|---|
| 400 | Invalid request (bad params) | Fix the request body |
| 401 | Invalid API key | Check your api_key value |
| 403 | Insufficient permissions | Verify key permissions in dashboard |
| 404 | Model not found | Check model name in supported models |
| 429 | Rate limit exceeded | SDK retries automatically; reduce concurrency |
| 500 | Server error | Retry; SandBase auto-routes to fallback providers |
| 503 | Provider unavailable | Retry; SandBase auto-routes to fallback providers |
Async Client
For high-concurrency applications, use the async clients:
OpenAI Async
import asyncio
from openai import AsyncOpenAI
client = AsyncOpenAI(
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key"
)
async def process_batch(prompts: list[str]):
"""Process multiple prompts concurrently."""
tasks = [
client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
for prompt in prompts
]
responses = await asyncio.gather(*tasks)
return [r.choices[0].message.content for r in responses]
results = asyncio.run(process_batch([
"What is 2+2?",
"What is the capital of Japan?",
"Name a primary color",
]))Anthropic Async
import asyncio
import anthropic
client = anthropic.AsyncAnthropic(
base_url="https://api.sandbase.ai",
api_key="sk-sb-your-key"
)
async def ask(question: str) -> str:
response = await client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
messages=[{"role": "user", "content": question}]
)
return response.content[0].text
result = asyncio.run(ask("What is the meaning of life?"))
print(result)Framework Integration
LangChain
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4o",
base_url="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key",
)
response = llm.invoke("What is the capital of France?")
print(response.content)LlamaIndex
from llama_index.llms.openai import OpenAI
llm = OpenAI(
model="gpt-4o",
api_base="https://api.sandbase.ai/v1",
api_key="sk-sb-your-key",
)
response = llm.complete("What is the capital of France?")
print(response.text)Sandbox Operations
Use the requests library for sandbox API calls (not covered by OpenAI/Anthropic SDKs):
import requests
BASE_URL = "https://api.sandbase.ai"
HEADERS = {"Authorization": "Bearer sk-sb-your-key"}
# Create a sandbox
response = requests.post(
f"{BASE_URL}/sandboxes",
headers=HEADERS,
json={"templateID": "code_interpreter", "timeout": 300}
)
sandbox = response.json()
sandbox_id = sandbox["sandboxID"]
print(f"Created sandbox: {sandbox_id}")
# Execute code
exec_response = requests.post(
f"{BASE_URL}/sandboxes/{sandbox_id}/processes",
headers=HEADERS,
json={
"cmd": "python3",
"args": ["-c", "import numpy as np; print(np.random.rand(3))"]
}
)
result = exec_response.json()
print(f"Output: {result['stdout']}")
# Shutdown when done
requests.post(f"{BASE_URL}/sandboxes/{sandbox_id}/shutdown", headers=HEADERS)Next Steps
- JavaScript / TypeScript SDK — Same pattern, different language
- Supported Models — Full list of 1400+ available models
- Model Routing — Smart routing strategies
- Streaming Guide — Deep dive into SSE streaming
- API Reference — Full endpoint documentation

