Call OpenRouter from Python and inspect the model that actually served the response. Add a deliberate invalid-model branch and detect body errors before reading completion content.
What you'll build
This script establishes a minimal request path through OpenRouter. It prints the answer, resolved model, completion reason and usage when returned. It also stops if a response body contains an error or lacks completion choices, making the distinction between HTTP transport and model completion visible.
The official quickstart supplies a native OpenRouter Python SDK. This tutorial uses that native client. Official documentation.
The script selects the concrete catalog slug openai/gpt-5.6-sol rather than a moving family alias. Use OPENROUTER_MODEL to change the selected model, and preserve that choice with the fixture. Official documentation.
Printing the returned model keeps the request traceable even when you later choose an alias or add routing options. An evaluation should not confuse model movement with a prompt improvement.
Prerequisites
Complete the OpenRouter API-key guide and make the credential available as OPENROUTER_API_KEY. Check the workspace and key credit controls before making the request.
Use a safe synthetic task and an application-specific Python environment. Keep the chosen interpreter and installed client version in your experiment record. If the script fails before a provider response arrives, identify the local stage first instead of changing the model or creating a new secret.
Review any account routing preferences that could exclude endpoints. A small request can still fail when its mandatory settings leave no eligible route. The first test is useful precisely because it keeps that eligibility diagnosis separate from a complex application payload.
Install SDK
python -m pip install --upgrade openrouter
Save the full example as first_openrouter.py in the application workspace. Configure the environment secret through the launch method you use, then invoke the script from the same interpreter. Do not paste the secret into the source file or into a shared command transcript.
python first_openrouter.py
Running this command with an active key makes a real provider request. Inspect the first result and account state before repeating it. The tutorial’s displayed response is a schematic illustration and does not claim that an inference run occurred on your account.
Full script
import os
import sys
import json
import httpx
from openrouter import OpenRouter
from openrouter.errors import OpenRouterError
model = os.environ.get("OPENROUTER_MODEL", "openai/gpt-5.6-sol")
if "--bad-model" in sys.argv:
model = "ai-api-hub/invalid-model"
try:
with OpenRouter(api_key=os.environ["OPENROUTER_API_KEY"]) as client:
result = client.chat.send(
model=model,
messages=[{"role":"user","content":"Explain why an API response should identify the model used, in one sentence."}],
max_tokens=512,
stream=False,
timeout_ms=60000,
retries=None,
)
payload = result.model_dump()
if payload.get("error"):
print(json.dumps(payload["error"], ensure_ascii=False))
raise SystemExit(1)
if not result.choices:
raise SystemExit("No completion choices returned")
print(result.choices[0].message.content)
print("Resolved model:", result.model)
print("finish_reason:", result.choices[0].finish_reason)
print(result.usage.model_dump_json() if result.usage else "Usage unavailable")
except OpenRouterError as exc:
print(f"HTTP {exc.status_code}")
print(exc.body)
raise SystemExit(1)
except httpx.TimeoutException:
raise SystemExit("Request timed out; inspect the task before resubmitting")
The SDK method accepts a request timeout and a retry override. The script disables SDK retries for this diagnostic call and prints the native HTTP error body. Official documentation.
A later worker can add a bounded retry policy after distinguishing temporary failures from invalid requests and credit conditions. Keep one layer responsible for retries.
The body check is deliberate. A service can begin a successful HTTP response and then encounter a generation failure. The application should detect that error shape before accessing choices. Keep output validation as a further step even when a normal completion exists.
Expected output
The following text is schematic, not an observed inference response. The model field identifies the target that served the request. Wording, usage and completion details will come from the actual result.
The model identity makes an API result traceable and its behavior easier to compare.
Resolved model: openai/gpt-5.6-sol
finish_reason: stop
{"prompt_tokens":16,"completion_tokens":20,"total_tokens":36}
Check that the sentence answers the requested question and that the completion state is acceptable. Save safe usage metadata with the fixture rather than only copying the attractive sentence. That record becomes useful when you switch a route or add a required output format.
One deliberate error and its fix
python first_openrouter.py --bad-model
The deliberate branch supplies an invalid catalog identifier. The handler prints the actual error body it receives, allowing you to test the failure path without creating excessive traffic or intentionally exhausting a budget. Keep the result redacted if you share it.
Repair the test by selecting an available concrete slug or restoring the documented alias and running the ordinary command. Do not resubmit the unchanged invalid request in a retry loop. If the ordinary command fails too, inspect its own error rather than assuming the wrong-model diagnosis applies.
{"error":{"code":400,"message":"Schematic: invalid model identifier."}}
The JSON above illustrates a possible envelope only. Your provider response establishes its actual status, wording and typed metadata. Keep a test harness that can handle an unfamiliar error shape without turning it into a success.
What this request costs
Estimate your API costs
Your text and estimates stay in this browser. No API requests are sent to model providers.
Loading verified model records…
Use the preset model in the OpenRouter calculator with actual returned usage. If you override the model or choose an alias, select the concrete returned model before estimating its charge categories.
For a larger application, add the output requirement, request volume and permitted fallback routes. Include repair calls and optional hosted features where applicable. The cost of one short demonstration should not be presented as the complete economics of a multi-stage agent.
Next steps
Pin a concrete model for a controlled baseline, then add one mandatory feature at a time. If you introduce structured output or tools, verify endpoint support and validate the result in application code. Preserve the first passing fixture so a later routing change can be compared with a known request.
Read model slugs and aliases, body-aware error handling and OpenRouter versus direct calls before widening the integration.
Finish with a short operating record: workspace, secret owner, request interface, concrete evaluated model, accepted fixtures and stop conditions. This record gives the next developer enough context to reproduce the integration without seeing the secret or guessing how routing was configured.
Last verified · Source ↗
Frequently asked questions
Which Python client and credential does this example use?
Why print the resolved model?
Why inspect an error field before choices?
Was the sample output observed?
How do I make a reproducible model baseline?
What should the deliberate error establish?
Sources
- OpenRouter quickstart ↗
- Models and pricing schema ↗
- Authentication ↗
- Credit and rate limits ↗
- Errors and debugging ↗
- Provider routing ↗
- Free model variants ↗
- Free router ↗
- Workspace budgets ↗
- Prompt caching ↗
- BYOK ↗
- Provider logging ↗
- Batch quickstart ↗
- Latest aliases ↗
- Official Python SDK source ↗
Last verified · Source ↗