{"slug": "access-multiple-ai-models-in-your-python-apps-using-openrouter", "title": "Access Multiple AI Models in Your Python Apps Using OpenRouter", "summary": "OpenRouter exposes dozens of AI model providers through a single HTTP API, letting Python developers switch between models such as GPT, Claude and Llama by changing one string rather than building separate integrations, according to a tutorial published on the OpenRouter platform. The tutorial walks through creating a free OpenRouter account, generating an API key stored as the OPENROUTER_API_KEY environment variable, and sending requests with the Python requests library to a single POST endpoint, with no SDK required. It notes that models marked with a :free suffix and the openrouter/free alias let readers run every example at zero cost, and that OpenRouter also offers an official openrouter SDK for typed client objects.", "body_md": "# Access Multiple AI Models in Your Python Apps Using OpenRouter\n\nLearn how to get started with the OpenRouter API to call multiple AI models through one API, compare responses, switch models, and set up automatic fallbacks.\n\n## Introduction\n\nSay you're building a support-ticket assistant, and you want to compare how **[GPT](https://platform.openai.com/docs/models)**, **[Claude](https://www.anthropic.com/claude)**, and **[Llama](https://www.llama.com/)** each handle the same customer message before picking one. Normally that means signing up with three separate providers, learning three different authentication schemes, and rewriting your request code three times just to run one comparison.\n\n**[OpenRouter](https://openrouter.ai/)** removes that repetition. It sits in front of dozens of providers and exposes them through a single API, so switching from one model to another is a one-line change instead of a new integration. Your Python code stays exactly the same regardless of which provider is actually answering the request. This article covers:\n\n- Creating an OpenRouter account and getting an API key\n- Sending your first request to a model with plain Python and **[requests](https://pypi.org/project/requests/)**\n- Switching models by changing a single string, with no other code changes\n- Letting OpenRouter pick a model automatically, and adding backup models for reliability\n\nWe'll build this up one small script at a time, starting with the account setup.\n\n## Prerequisites\n\nYou don't need any AI or machine learning background to follow along. You do, however, need to be comfortable with basic Python, installing packages with `pip`, and setting an environment variable in your terminal. OpenRouter handles the model integration, so your code only sends text and reads the response.\n\n## Creating an OpenRouter Account and API Key\n\nGo to OpenRouter and create a free account. Once you're signed in, open the **Keys** section from your account menu and generate a new API key. Give it a name you'll recognize later, like `learning-key`, and leave the other settings on their defaults.\n\nCopy the key somewhere safe. Store it as an environment variable so it never ends up committed to a repository by accident.\n\nOn macOS or Linux:\n\n```\nexport OPENROUTER_API_KEY=\"your-key-here\"\n```\n\n**TL;DR:** Some models on OpenRouter are free to try, so you can follow this entire tutorial without adding a payment method.\n\n**More on the why and how:** OpenRouter marks certain models with a `:free` suffix; these route to fully free-to-use versions, with no payment method required. Every example in this tutorial uses one of these, so you can run all of it at zero cost. If a model ID in this tutorial stops responding by the time you read it, check the current list at [**openrouter.ai/models**](https://openrouter.ai/models) filtered to free, or swap in `openrouter/free`, which we'll cover below and which always resolves to whichever free model is currently available.\n\n## Setting Up Your Project\n\nCreate a folder for the project and a virtual environment inside it:\n\n```\nmkdir support-bot-demo\ncd support-bot-demo\npython -m venv .venv\nsource .venv/bin/activate\n```\n\nWith the environment active, install `requests`. It is the only dependency you need. OpenRouter is a plain HTTP API, so there's no special software development kit (SDK) required to get started:\n\n```\npip install requests\n```\n\n**Note**: OpenRouter does have an official SDK too. You can install `openrouter` with `pip`, which provides typed client objects instead of raw dictionaries.\n\nThis tutorial only uses `requests` so every request stays visible as plain JSON, making it easier to see exactly what is being sent and received while you're still learning how the API is shaped. Once you get the hang of it, moving to the SDK later is a small change.\n\n## Sending Your First Request to a Model\n\nEvery request to OpenRouter looks the same regardless of which model answers it: a `POST` request to one endpoint, with your API key in the headers and a list of messages in the body. Here's a script that sends a customer support message to a model and prints the reply:\n\n``` python\nimport os\nimport requests\n\nAPI_URL = \"https://openrouter.ai/api/v1/chat/completions\"\nAPI_KEY = os.getenv(\"OPENROUTER_API_KEY\")\n\ncustomer_message = (\n    \"My order #48213 arrived with the wrong charger. \"\n    \"I need the correct one before Friday, can you help?\"\n)\n\npayload = {\n    \"model\": \"meta-llama/llama-3.2-3b-instruct:free\",\n    \"messages\": [\n        {\"role\": \"system\", \"content\": \"You are a concise, polite customer support agent.\"},\n        {\"role\": \"user\", \"content\": customer_message},\n    ],\n}\n\nheaders = {\n    \"Authorization\": f\"Bearer {API_KEY}\",\n    \"Content-Type\": \"application/json\",\n}\n\nresponse = requests.post(API_URL, headers=headers, json=payload)\ndata = response.json()\n\nprint(f\"Model used: {data['model']}\")\nprint(f\"Reply: {data['choices'][0]['message']['content']}\")\n```\n\nThe `payload` dictionary is the entire request: `model` tells OpenRouter which model to use, written as `provider/model-name`, and `messages` follows the same role/content format you'd use with any chat-style model.\n\nThe system message sets the tone once, and the user message is the actual ticket text. The response comes back as JSON, and the reply text is in `data[\"choices\"][0][\"message\"][\"content\"]` — the same shape you'd get from most chat completion APIs, since OpenRouter normalizes every provider's response into the same OpenAI-compatible format.\n\n## Switching Models Without Changing Your Code\n\nSince the model is just a string in the payload, comparing providers means changing one line. Here's a small function that takes the model name as an argument, so you can call it with different models back to back:\n\n``` python\ndef ask_model(model_name, message):\n    payload = {\n        \"model\": model_name,\n        \"messages\": [\n            {\"role\": \"system\", \"content\": \"You are a concise, polite customer support agent.\"},\n            {\"role\": \"user\", \"content\": message},\n        ],\n    }\n    response = requests.post(API_URL, headers=headers, json=payload)\n    return response.json()\n\nticket = \"My order #48213 arrived with the wrong charger. I need the correct one before Friday.\"\n\nfor model in [\"meta-llama/llama-3.2-3b-instruct:free\", \"qwen/qwen3-4b:free\", \"mistralai/mistral-7b-instruct:free\"]:\n    result = ask_model(model, ticket)\n    reply = result[\"choices\"][0][\"message\"][\"content\"]\n    print(f\"--- {model} ---\")\n    print(reply, \"\\n\")\n```\n\n`ask_model` is the same request logic from the first script (it reuses `API_URL` and `headers` from there), only wrapped so `model_name` is a parameter instead of a hardcoded value. The loop calls it three times with three different models and prints each reply next to the model that produced it. This is the core benefit of OpenRouter in practice: you're calling one function three times instead of working with three different APIs.\n\n## Letting OpenRouter Pick a Free Model for You\n\nSometimes you don't care which specific model answers; you just want a working reply without picking one yourself, and without any risk of a paid model slipping in. Setting `model` to `openrouter/free` hands that decision to OpenRouter's [**Free Models Router**](https://openrouter.ai/docs/guides/routing/routers/free-router), which always selects from currently available free models:\n\n```\npayload = {\n    \"model\": \"openrouter/free\",\n    \"messages\": [{\"role\": \"user\", \"content\": ticket}],\n}\nresponse = requests.post(API_URL, headers=headers, json=payload)\ndata = response.json()\n\nprint(f\"OpenRouter picked: {data['model']}\")\n```\n\nThis is the safest default for prototyping: no matter which free model happens to be available that day, you're never charged. It's a different setting from `openrouter/auto`, which picks whatever model best fits the prompt and can include paid ones.\n\nSeparately, when you do specify a model by name, OpenRouter often has more than one provider hosting it, and you can choose which one it uses with a `provider` field. For example, set `payload[\"provider\"] = {\"sort\": \"price\"}` to favor the cheapest provider, or `{\"sort\": \"latency\"}` to favor the fastest one. This matters most once you're working with paid models at real volume; it has little effect on `:free` models, since there's no per-token cost to optimize against in the first place.\n\n## Adding Fallback Models for Reliability\n\nA single model can fail due to a provider outage, a rate limit, a content filter rejecting the request, and much more. For anything beyond a super small side project, you want a backup ready automatically instead of your app crashing on the first failure. OpenRouter supports this by accepting a list of models instead of one:\n\n```\npayload = {\n    \"models\": [\n        \"qwen/qwen3-4b:free\",\n        \"meta-llama/llama-3.2-3b-instruct:free\",\n        \"mistralai/mistral-7b-instruct:free\",\n    ],\n    \"messages\": [{\"role\": \"user\", \"content\": ticket}],\n}\nresponse = requests.post(API_URL, headers=headers, json=payload)\ndata = response.json()\n\nprint(f\"Answered by: {data['model']}\")\nprint(data[\"choices\"][0][\"message\"][\"content\"])\n```\n\nNotice the key changed from `model` (singular) to `models` (a list). OpenRouter tries each entry in order and returns the first one that succeeds, so your code doesn't need any retry logic of its own. Order the list by what best suits your app, for example the highest quality first with cheaper backups, or the fastest first with more reliable backups further down.\n\n## Wrapping Up\n\nHere's an overview of everything we've covered in this introductory article and when you'd use each:\n\n| Feature | What It Does | When To Use It | \n|---|---|---|\n| A single model string with a `:free` tag | Targets one specific free model by name | When you need a predictable model with zero cost | \n| Swapping the `model` value | Lets you compare models with no other code changes | When testing which model fits your use case best | \n| `\"model\": \"openrouter/free\"` | Lets OpenRouter pick any available free model for you | Quick prototyping with a guaranteed-zero-cost default | \n| `\"provider\": {\"sort\": \"price\"}` or`{\"sort\": \"latency\"}` | Picks a provider for your chosen model based on cost or speed | Working with paid models at a considerable volume | \n| `\"models\": [...]` (a list) | Tries each model in order until one succeeds | Apps that need to stay up if one model fails | \n\nWith these basics, you can build anything from a quick one-off script to a support bot that stays online even when a single provider goes down.\n\nAs always, here are a couple of resources for further reading:\n\nKeep exploring!\n\n \n\n \n\n**[Bala Priya](https://github.com/balapriyac)** is a developer, educator, and technical writer based in India. She writes about programming, data science, machine learning, and AI, with a focus on making complex technical ideas practical and approachable.\nShe creates tutorials, how-to guides, and deep dives that help developers build, solve problems, and understand complex technical concepts. Her technical interests include LLM applications, agentic AI, graph algorithms, computer vision, explainable AI, and ML systems.\nWhen she’s not writing or coding, Bala is usually reading classic literature, epic fantasy, or speculative fiction... with a cup of coffee close by. She also enjoys talking about books, learning new things, and sharing what she learns with the developer community.", "url": "https://wpnews.pro/news/access-multiple-ai-models-in-your-python-apps-using-openrouter", "canonical_source": "https://www.kdnuggets.com/access-multiple-ai-models-in-your-python-apps-using-openrouter", "published_at": "2026-10-28 14:00:00+00:00", "updated_at": "2026-10-28 14:12:51.373330+00:00", "lang": "en", "topics": ["ai-products", "developer-tools", "large-language-models", "ai-tools"], "entities": ["OpenRouter", "GPT", "Claude", "Llama", "OpenAI", "Anthropic", "Python", "requests"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/access-multiple-ai-models-in-your-python-apps-using-openrouter", "markdown": "https://wpnews.pro/news/access-multiple-ai-models-in-your-python-apps-using-openrouter.md", "text": "https://wpnews.pro/news/access-multiple-ai-models-in-your-python-apps-using-openrouter.txt", "jsonld": "https://wpnews.pro/news/access-multiple-ai-models-in-your-python-apps-using-openrouter.jsonld"}}