Call any model with the OpenAI SDK

· Hyperouter · 2 min read

Hyperouter speaks OpenAI's API. Any OpenAI SDK works once you change two things: the base URL and the API key. This guide makes a chat call and an image call in Python and TypeScript.

1. Get a key

Sign in with Google or GitHub and create an API key. Keys start with sk-hr-v1- and are shown once, so keep yours in an environment variable:

export HYPEROUTER_API_KEY="sk-hr-v1-..."

Requests are paid from your prepaid balance: open a top-up request in the dashboard before your first call. Keep the key on your server, never in browser or mobile code.

2. Point the SDK at Hyperouter

The base URL is https://api.hyperouter.app/v1.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.hyperouter.app/v1",
    api_key=os.environ["HYPEROUTER_API_KEY"],
)

3. Chat

Name a model by its Hyperouter id, <provider>/<name>. This call uses xAI's Grok 4.3:

res = client.chat.completions.create(
    model="x-ai/grok-4.3",
    messages=[{"role": "user", "content": "Explain idempotency in one sentence."}],
)
print(res.choices[0].message.content)

The answer is OpenAI's chat completion with two additions: provider, the provider that served the request, and usage.cost, its charge in USD. Set stream: true to receive server-sent events, as with OpenAI.

To fall back to other models when every provider of the first one fails, list them in models. The OpenAI SDKs send it as an extra body field:

res = client.chat.completions.create(
    model="x-ai/grok-4.3",
    messages=[{"role": "user", "content": "Hello"}],
    extra_body={"models": ["x-ai/grok-4.20-0309-non-reasoning"]},
)

4. Images

The Images API works the same way. This call makes one picture with Grok Imagine:

img = client.images.generate(
    model="x-ai/grok-imagine-image",
    prompt="A lighthouse at dusk",
)
print(img.data[0].url)

The link is signed and valid for 24 hours, and GET /v1/generations/{id} signs a fresh one. qwen/qwen-image-2.0 is called the same way. On a model that answers synchronously, an image that is not ready within 90 seconds answers 503 with code timeout and its generation_id; Waiting for the result explains how to poll for it instead.

What next