{"slug": "i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini", "title": "I pointed the OpenAI SDK at one base URL and got Claude, GPT and Gemini", "summary": "A developer demonstrated that by pointing the OpenAI SDK at the base URL of api.airforce, a single client can access models from Claude, GPT, and Gemini by simply changing the model string. The gateway provides cross-provider failover, a free tier, and support for text, image, audio, and video under one API key.", "body_md": "Here's the whole trick, up front. You keep the official OpenAI SDK, change the base URL, and the same client now talks to Claude, GPT and Gemini — you only swap the `model`\n\nstring:\n\n**Python**\n\n``` python\nfrom openai import OpenAI\n\nclient = OpenAI(\n    base_url=\"https://api.airforce/v1\",\n    api_key=\"YOUR_KEY\",\n)\n\nfor model in [\"claude-sonnet-4.6\", \"gpt-5.1\", \"gemini-3-pro\"]:\n    resp = client.chat.completions.create(\n        model=model,\n        messages=[{\"role\": \"user\", \"content\": \"Say hi in one short sentence.\"}],\n    )\n    print(model, \"->\", resp.choices[0].message.content)\n```\n\nSame client, three providers, no `if provider == ...`\n\nbranching. That's the part worth a blog post.\n\nThe reason this works is that api.airforce is an OpenAI-compatible gateway: one base URL (`https://api.airforce/v1`\n\n), one API key, and a single catalog of models you address by name. The pain it removes is the usual one — a separate account for each vendor, a separate SDK, a separate billing dashboard, and glue code to keep them apart. Here it's one of each.\n\nYou don't learn a new SDK. You reuse the OpenAI one and change two lines.\n\n**TypeScript / JavaScript**\n\n``` python\nimport OpenAI from \"openai\";\n\nconst client = new OpenAI({\n  baseURL: \"https://api.airforce/v1\",\n  apiKey: process.env.AIRFORCE_KEY,\n});\n\nconst resp = await client.chat.completions.create({\n  model: \"gpt-5.1\", // or claude-sonnet-4.6, gemini-3-pro, ...\n  messages: [{ role: \"user\", content: \"Give me a haiku about caching.\" }],\n});\nconsole.log(resp.choices[0].message.content);\n```\n\n**curl**\n\n```\ncurl https://api.airforce/v1/chat/completions \\\n  -H \"Authorization: Bearer $AIRFORCE_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"claude-sonnet-4.6\",\n    \"messages\": [{\"role\": \"user\", \"content\": \"Hello!\"}]\n  }'\n```\n\nWant a different model? Change the `model`\n\nstring — no new client, no new account, no new key. Model names follow each provider's own convention, and versions move, so treat the strings above as examples: the current list is `GET https://api.airforce/v1/models`\n\n(and the [docs](https://api.airforce/docs/)).\n\nThe same key reaches more than text models:\n\nSo a multi-modal app talks to one endpoint instead of stitching several vendors together. As always, check `/v1/models`\n\nfor which ids are live before you wire one in.\n\nThis is the part I actually care about more than the convenience. For a given model, the gateway routes across multiple upstream providers, so when one upstream returns a 429 or a 5xx, the call is retried on another provider transparently — you get one response back and don't see the failure. From your code it's still just one model name; the failover lives behind the base URL. That's the real difference from calling a single vendor directly, where a rate-limit on their side is your outage too.\n\nIt's pay-as-you-go with a genuine free tier, so you're not forced into a monthly seat to try it — prototype on the free tier, then keep the exact same code in production. There are optional paid plans on top if you want them, but nothing stops you from starting at $0.\n\nSame category — a multi-provider, OpenAI-compatible gateway — and if you've used OpenRouter the mental model is identical: point your client at one URL, address many models by name. I'm not going to pretend OpenRouter isn't good; it does at-cost passthrough pricing with a small credit fee and has a solid set of free models, and plenty of people are happy on it.\n\nWhat api.airforce leans on are a large free tier with light limits, text + image + audio + video under one key, the cross-provider failover above, and official client libraries in several languages if you'd rather not use the raw OpenAI client (TypeScript, Python, Go, Java, C#, Rust, Dart, PHP — see the docs for the current set). I'm deliberately not making a blanket \"it's cheaper\" claim: prices move per model on every gateway, so if cost is your deciding factor, compare the specific model you'll actually use, on the day you choose, against whatever you run now. The honest takeaway is narrower: the *unified-gateway* pattern itself saves you a lot of glue code, whichever provider you land on.\n\nIf you're already on a gateway or wiring providers up by hand, swapping the base URL is a five-minute experiment. How are you handling cross-provider failover today — retries in app code, a gateway, or just eating the occasional 429? Curious how others do it.", "url": "https://wpnews.pro/news/i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini", "canonical_source": "https://dev.to/airforceapi/i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini-38mf", "published_at": "2026-06-16 20:00:09+00:00", "updated_at": "2026-06-16 20:17:10.085682+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models", "generative-ai", "ai-infrastructure"], "entities": ["OpenAI", "api.airforce", "Claude", "GPT", "Gemini", "OpenRouter"], "alternates": {"html": "https://wpnews.pro/news/i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini", "markdown": "https://wpnews.pro/news/i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini.md", "text": "https://wpnews.pro/news/i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini.txt", "jsonld": "https://wpnews.pro/news/i-pointed-the-openai-sdk-at-one-base-url-and-got-claude-gpt-and-gemini.jsonld"}}