Developer tools

Python SDK

pip install routeplane. Change one line to keep the stock OpenAI client, add typed steering headers to any client, or use the full Routeplane client with async, streaming, and typed response metadata.

The official Python SDK for Routeplane. It meets you at whatever level of integration you want: change one line and keep the stock OpenAI client, add typed steering headers to any client, or use the full Routeplane client for auth, default routing, and typed response metadata. Requires Python 3.9+.

pythonPyPI
pip install routeplane

Minimal — just change base_url

If you already use the OpenAI SDK, point it at the gateway and pass your virtual key. Nothing else changes.

pythonstock openai client
import openai

client = openai.OpenAI(
    api_key="rp_your_gateway_key",
    base_url="https://api.routeplane.ai/v1",
    default_headers={"x-routeplane-api-key": "rp_your_gateway_key"},
)

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)

Steer any client with headers()

Routeplane's per-request behaviour is configured through x-routeplane-* headers. headers() is a typed builder for them: it emits only the options you set, JSON-serializes dict values (config, metadata), and stringifies ints (timeout_ms). Because it returns a plain dict, it drops into any client's extra-headers escape hatch — not just this SDK.

pythonopenai + headers()
import openai
from routeplane import headers

client = openai.OpenAI(
    api_key="rp_your_gateway_key",
    base_url="https://api.routeplane.ai/v1",
    default_headers={"x-routeplane-api-key": "rp_your_gateway_key"},
)

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Summarize this contract."}],
    extra_headers=headers(
        provider="anthropic,openai",   # fallback chain
        strategy="cost",               # cheapest eligible provider first
        residency="IN",                # keep Indian PII in-region
        use_case="contract-summary",   # shows up in FinOps
    ),
)

All 17 request headers are typed. See the reference below.

The Routeplane client

Routeplane subclasses openai.OpenAI, so everything works exactly as before — but it wires up auth, lets you set default routing once, and can parse the gateway's response headers into a typed RouteplaneMeta. Per-call extra_headers=headers(...) still override the client defaults.

pythonRouteplane client
from routeplane import Routeplane

client = Routeplane(
    api_key="rp_your_gateway_key",
    provider="openai,anthropic",   # client-wide default fallback chain
    strategy="latency",
    residency="IN",
    use_case="support-bot",
)

# Ordinary call — same OpenAI API you already know.
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hi"}],
)

Response metadata

create_with_meta returns the completion and a typed RouteplaneMeta decoded from the gateway's response headers — so you can see what the gateway actually did.

pythoncreate_with_meta
completion, meta = client.create_with_meta(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What is DPDP?"}],
)

print(meta.provider)          # which provider actually served it
print(meta.cache)             # "hit" | "miss" | "bypass"
print(meta.budget_remaining)  # spend headroom
print(meta.pii_masked)        # was PII masked on the way out?

If you prefer to stay on the raw OpenAI API, client.meta_from_headers(raw.headers) parses the same metadata from a with_raw_response call. RouteplaneMeta exposes provider, trace_id, request_id, cache, guardrails, hedged, shed, budget_remaining, budget_warning, compliance_warning, pii_masked, and idempotent_replayed.

Streaming with metadata

stream_with_meta returns an iterable whose .meta is populated from the response headers — which arrive before the first chunk — so you can read which provider served the request immediately, then consume the stream.

pythonstream_with_meta
stream = client.stream_with_meta(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Explain sovereign routing"}],
)

print(f"Served by: {stream.meta.provider}")
for chunk in stream:
    content = chunk.choices[0].delta.content
    if content:
        print(content, end="")

Async

pythonAsyncRouteplane
from routeplane import AsyncRouteplane

client = AsyncRouteplane(api_key="rp_your_gateway_key", strategy="cost")

resp = await client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)

Beyond OpenAI — resource namespaces

The OpenAI-shaped surfaces (chat, embeddings) come from the inherited client. Everything Routeplane adds on top is exposed as typed namespaces on the Routeplane client:

NamespaceWhat it covers
client.promptsFetch and render stored prompt templates.
client.logsRecent request logs.
client.analyticsRecent usage analytics events.
client.finopsFinOps usage and daily rollups.
client.cacheResponse-cache stats and purge.
client.feedbackAttach quality scores to prior requests.
client.residencySovereign-routing decisions and ledger.
client.statusGateway health and per-provider circuit state.
client.rp_modelsThe gateway model catalog.
client.rp_providersCustom OpenAI-compatible providers.
client.mcp_securityAgentic-security MCP runs.

Why rp_models and rp_providers? The inherited OpenAI client already owns client.models, so the gateway's catalog is namespaced rp_models (and rp_providers, mcp_security) to avoid shadowing the base class.

Framework integrations

Because headers() returns a plain dict, it plugs into anything that forwards headers to the OpenAI API.

pythonLangChain
from langchain_openai import ChatOpenAI
from routeplane import headers

llm = ChatOpenAI(
    model="gpt-4o-mini",
    api_key="rp_your_gateway_key",
    base_url="https://api.routeplane.ai/v1",
    default_headers={
        "x-routeplane-api-key": "rp_your_gateway_key",
        **headers(provider="anthropic,openai", strategy="cost"),
    },
)
pythonLlamaIndex
from llama_index.llms.openai import OpenAI
from routeplane import headers

llm = OpenAI(
    model="gpt-4o-mini",
    api_key="rp_your_gateway_key",
    api_base="https://api.routeplane.ai/v1",
    default_headers={
        "x-routeplane-api-key": "rp_your_gateway_key",
        **headers(residency="IN", use_case="rag"),
    },
)
pythonCrewAI
from crewai import LLM
from routeplane import headers

llm = LLM(
    model="openai/gpt-4o-mini",
    base_url="https://api.routeplane.ai/v1",
    api_key="rp_your_gateway_key",
    extra_headers={
        "x-routeplane-api-key": "rp_your_gateway_key",
        **headers(strategy="latency", use_case="research-crew"),
    },
)

Request headers reference

All are x-routeplane-* and all are optional except the API key. Build them with headers(...).

OptionHeaderNotes
providerx-routeplane-providerProvider or comma-separated fallback chain.
residencyx-routeplane-residencyData-residency region (e.g. IN).
strategyx-routeplane-strategypriority | weighted | cost | latency.
configx-routeplane-configInline routing config (JSON).
timeout_msx-routeplane-timeout-msUpstream timeout, ms.
use_casex-routeplane-use-caseAnalytics / FinOps label.
log_levelx-routeplane-log-levelmetadata | none | full.
conversation_idx-routeplane-conversation-idGroups a conversation.
currencyx-routeplane-currencyCost-reporting currency.
metadatax-routeplane-metadataArbitrary tags (JSON).
pii_modex-routeplane-pii-modetokenize.
output_maskx-routeplane-output-maskOutput masking policy.
cache_controlx-routeplane-cache-controlno-store.
idempotency_keyx-routeplane-idempotency-keySafe-retry key.
cohortx-routeplane-cohortExperiment cohort.
batchx-routeplane-batchBatch id.
trace_idx-routeplane-trace-idClient trace id (echoed back).