{"id":56,"library":"openrouter","title":"OpenRouter Python SDK","description":"Official Python SDK for the OpenRouter API — a unified gateway to 300+ LLM models across providers (OpenAI, Anthropic, Google, Meta, Mistral, etc.) via a single OpenAI-compatible endpoint. Auto-generated from OpenRouter's OpenAPI spec and updated on every API change. Fully typed with Pydantic. SDK is explicitly in beta — breaking changes can occur between minor versions without a major version bump. IMPORTANT: There are multiple competing 'openrouter' packages on PyPI (openrouter, openrouter-client, python-open-router). Only 'openrouter' (by OpenRouter) is the official SDK.","status":"active","version":"0.7.11","language":"python","source_language":"en","source_url":"https://github.com/OpenRouterTeam/python-sdk","tags":["openrouter","llm-gateway","multi-model","openai-compatible","anthropic","model-routing","unified-api","beta"],"install":[{"cmd":"pip install openrouter","lang":"bash","label":"Official SDK (pin to specific version — SDK is in beta)"},{"cmd":"pip install openrouter==0.7.11","lang":"bash","label":"Pinned install (recommended per SDK docs)"}],"dependencies":[{"reason":"Required. Used for sync and async HTTP transport.","package":"httpx","optional":false},{"reason":"Required. All request and response objects are Pydantic models.","package":"pydantic","optional":false}],"imports":[{"note":"Use as context manager: 'with OpenRouter(api_key=...) as client'. This ensures HTTPX connections are properly closed.","wrong":"import openrouter; openrouter.client()","symbol":"OpenRouter","correct":"from openrouter import OpenRouter"}],"quickstart":{"code":"import os\nfrom openrouter import OpenRouter\n\n# Sync usage — use as context manager\nwith OpenRouter(api_key=os.environ['OPENROUTER_API_KEY']) as client:\n    # Standard completion\n    response = client.chat.send(\n        model='anthropic/claude-sonnet-4-20250514',\n        messages=[{'role': 'user', 'content': 'Hello!'}]\n    )\n    print(response)\n\n    # With provider routing preferences\n    response = client.chat.send(\n        model='openai/gpt-4o',\n        messages=[{'role': 'user', 'content': 'Hello!'}],\n        provider={\n            'sort': 'price',  # or 'latency', 'throughput'\n            'zdr': True       # Zero Data Retention\n        }\n    )\n\n# Async usage\nimport asyncio\nfrom openrouter import OpenRouter\n\nasync def main():\n    async with OpenRouter(api_key=os.environ['OPENROUTER_API_KEY']) as client:\n        response = await client.chat.send_async(\n            model='anthropic/claude-sonnet-4-20250514',\n            messages=[{'role': 'user', 'content': 'Hello!'}]\n        )\n        print(response)\n\nasyncio.run(main())\n\n# OpenAI SDK approach (no openrouter package needed)\nfrom openai import OpenAI\nclient = OpenAI(\n    api_key=os.environ['OPENROUTER_API_KEY'],\n    base_url='https://openrouter.ai/api/v1'\n)\nresponse = client.chat.completions.create(\n    model='anthropic/claude-sonnet-4-20250514',\n    messages=[{'role': 'user', 'content': 'Hello!'}]\n)","lang":"python","description":"Always use OpenRouter as a context manager to ensure HTTPX connections are released. The OpenAI SDK approach (with base_url override) is simpler and more widely used in practice — consider it as a primary option if you already have openai installed."},"warnings":[{"fix":"Pin to an exact version: pip install openrouter==0.7.11. Do not use unpinned installs in production.","message":"SDK is explicitly in beta. The PyPI page states: 'breaking changes between versions without a major version update'. The SDK jumped from 0.0.x to 0.1.x to 0.6.0 to 0.7.x with no major version bump. Each jump contained breaking API changes.","severity":"breaking","affected_versions":"all"},{"fix":"Only install 'openrouter' (the official SDK by OpenRouter). Verify with: pip show openrouter — author should be 'OpenRouter', license 'Apache-2.0'.","message":"Multiple competing packages on PyPI share similar names: 'openrouter' (official), 'openrouter-client' (unofficial FastAPI wrapper), 'python-open-router' (unofficial async client). pip install openrouter-client or pip install python-open-router install the wrong package with different APIs.","severity":"gotcha","affected_versions":"all"},{"fix":"Always use: 'with OpenRouter(api_key=...) as client:' (sync) or 'async with OpenRouter(api_key=...) as client:' (async).","message":"Not using OpenRouter as a context manager leaves HTTPX client connections open (file handles, sockets). In long-running services or scripts that repeatedly instantiate OpenRouter(), this causes connection pool exhaustion.","severity":"gotcha","affected_versions":"all"},{"fix":"Always use 'provider/model-name' format. Browse available models at openrouter.ai/models.","message":"OpenRouter model strings include the provider prefix: 'anthropic/claude-sonnet-4-20250514', not just 'claude-sonnet-4-20250514'. Using just the model name without provider prefix may fail or route to an unexpected provider.","severity":"gotcha","affected_versions":"all"},{"fix":"For simple use cases, consider: from openai import OpenAI; client = OpenAI(api_key=OPENROUTER_API_KEY, base_url='https://openrouter.ai/api/v1'). No extra package needed.","message":"The OpenAI SDK approach (setting base_url='https://openrouter.ai/api/v1') is often simpler and more stable than the native openrouter package, especially for teams already using the openai SDK. The OpenRouter API is OpenAI-compatible by design.","severity":"gotcha","affected_versions":"all"},{"fix":"Ensure the `OPENROUTER_API_KEY` environment variable is correctly set in your execution environment before running the application. For example: `export OPENROUTER_API_KEY='YOUR_KEY_HERE'` or pass it via your deployment system.","message":"The SDK requires an API key for authentication, typically provided via the `OPENROUTER_API_KEY` environment variable. The `KeyError` indicates this environment variable was not found.","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T06:06:41.503Z","next_check":"2026-05-28T00:00:00.000Z","problems":[{"fix":"Ensure you have installed the *official* `openrouter` package by OpenRouter: `pip install openrouter`","cause":"This error occurs when the official `openrouter` Python SDK is not installed or when a different, unofficial package with a similar name is installed instead.","error":"ModuleNotFoundError: No module named 'openrouter'"},{"fix":"Set your OpenRouter API key as an environment variable named `OPENROUTER_API_KEY`. If using `python-dotenv`, ensure it's loaded. For direct client initialization, pass `api_key` explicitly. \n\n```python\nimport os\nfrom openrouter import OpenRouter\n\n# Ensure OPENROUTER_API_KEY is set in your environment or .env file\nclient = OpenRouter(api_key=os.getenv(\"OPENROUTER_API_KEY\"))\n\n# Or, if integrating with libraries like LiteLLM, ensure your .env has:\n# OPENROUTER_API_KEY=\"your_api_key_here\"\n# OPENAI_API_BASE=\"https://openrouter.ai/api/v1\"\n```","cause":"This typically occurs when the OpenRouter API key is missing or incorrectly configured, often due to using the wrong environment variable name (e.g., `OPENAI_API_KEY` instead of `OPENROUTER_API_KEY`) or an invalid key.","error":"AuthenticationError: OpenrouterException - {\"error\":{\"message\":\"No auth credentials found\",\"code\":401}}"},{"fix":"This issue often requires updates within the `pydantic-ai` library or handling specific OpenRouter error responses. For immediate workarounds, consider trying different models, adjusting request parameters (e.g., streaming settings), or implementing custom error parsing if directly using the OpenRouter API without strict Pydantic AI validation. Check for newer versions of `pydantic-ai` or `openrouter` that might have addressed this compatibility. A potential fix involves using `OpenRouterModel` from `pydantic_ai.models.openrouter` if available, or catching `UnexpectedModelBehavior` and inspecting the raw response if possible.","cause":"OpenRouter sometimes returns a `finish_reason` value (like 'error') that is not recognized or expected by the Pydantic AI's internal OpenAI-compatible schema, leading to a validation failure.","error":"pydantic_ai.exceptions.UnexpectedModelBehavior: Invalid response from OpenAI chat completions endpoint: 1 validation error for ChatCompletion choices.0.finish_reason Input should be 'stop', 'length', 'tool_calls', 'content_filter' or 'function_call' [type=literal_error, input_value='error', input_type=str]"},{"fix":"Choose an OpenRouter model that explicitly supports tool use. You can check the OpenRouter documentation or model listings to identify models compatible with function calling. \n\n```python\nfrom openrouter import OpenRouter\n\nclient = OpenRouter(api_key=os.getenv(\"OPENROUTER_API_KEY\"))\n\nresponse = client.chat.completions.create(\n    model=\"openrouter/your-tool-use-compatible-model\", # e.g., 'openai/gpt-4o' or other models listed as supporting tools\n    messages=[\n        {\"role\": \"user\", \"content\": \"What's the weather like in Paris?\"}\n    ],\n    tools=[\n        # Your tool definitions here\n    ]\n)\n```","cause":"This error indicates that the specific model you selected does not support the 'tool use' (function calling) feature that your request is attempting to leverage.","error":"{'message': 'No endpoints found that support tool use. To learn more about provider routing, visit: https://openrouter.ai/docs/provider-routing', 'code': 404}"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.57,"mem_mb":13.5,"disk_size":"35.6M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.59,"mem_mb":13.5,"disk_size":"35.1M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.42,"mem_mb":13.5,"disk_size":"35M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.44,"mem_mb":13.5,"disk_size":"35M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.85,"mem_mb":15,"disk_size":"39.0M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.82,"mem_mb":15,"disk_size":"38.5M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.71,"mem_mb":15,"disk_size":"39M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.7,"mem_mb":15,"disk_size":"38M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.95,"mem_mb":14.9,"disk_size":"30.4M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.92,"mem_mb":14.8,"disk_size":"30.0M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.93,"mem_mb":14.9,"disk_size":"30M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.93,"mem_mb":14.8,"disk_size":"30M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.95,"mem_mb":15.8,"disk_size":"30.1M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.94,"mem_mb":15.7,"disk_size":"29.6M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.9,"mem_mb":15.7,"disk_size":"30M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.87,"mem_mb":15.7,"disk_size":"29M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.57,"mem_mb":13.4,"disk_size":"34.9M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.56,"mem_mb":13.3,"disk_size":"34.5M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.52,"mem_mb":13.4,"disk_size":"35M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.51,"mem_mb":13.3,"disk_size":"34M"}]},"quickstart_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}