# SDKs & frameworks

> Connect the OpenAI SDKs, LangChain, Vercel AI SDK, LlamaIndex, and LiteLLM to INFRO. Every OpenAI-compatible tool works with one base URL and key.

Source: https://infro.io/docs/sdks

> **Note:** INFRO is in private early access. Running these examples requires an early-access account, an active trial or subscription entitlement, and your own provider connection. Self-serve purchasing is not generally open. See [Early access](https://infro.io/early-access).

First-party INFRO SDKs for Python, TypeScript and Dart are published at **0.1.3**; they give the image, video and audio endpoints a typed surface instead of hand-rolled JSON, and carry the INFRO extensions (`routing`, `fallbacks`, `logging`, `metadata`) as real arguments rather than an untyped extra-body dictionary. Install them with `pip install infro`, `npm install @infro.io/sdk` or `dart pub add infro`. The OpenAI-compatible path remains an alternative that needs no INFRO package: point any client that lets you override the OpenAI base URL at `https://api.infro.io/v1`, authenticate with an `sk_infro_...` key, and use [INFRO model IDs](https://infro.io/docs/models) like `anthropic/claude-sonnet-5` wherever the tool expects a model name.

The snippets below cover the most common SDKs and frameworks. If yours is not here, the integration is always the same two settings.

- `base_url` (string, required) — Always `https://api.infro.io/v1`. The setting name varies by client: `base_url` in the OpenAI Python SDK and LangChain, `baseURL` in the Node SDK and Vercel AI SDK, `api_base` in LlamaIndex and LiteLLM.
- `api_key` (string, required) — An INFRO key (`sk_infro_...`), created in the [console](https://dash.infro.io) — most clients read it from an environment variable. See [Authentication](https://infro.io/docs/authentication) for key labels and spend limits.

## OpenAI SDKs

The official OpenAI SDKs (`openai` on PyPI and npm) are the fastest migration path for existing OpenAI code — change the constructor arguments and the model name, keep everything else.

**Python**

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.infro.io/v1",
    api_key=os.environ["INFRO_API_KEY"],
)

response = client.chat.completions.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)
```

**TypeScript**

```typescript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.infro.io/v1",
  apiKey: process.env.INFRO_API_KEY,
});

const response = await client.chat.completions.create({
  model: "anthropic/claude-sonnet-5",
  messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content);
```

### INFRO extensions

INFRO-specific request fields — [`fallbacks`](https://infro.io/docs/features/fallbacks), [`logging`](https://infro.io/docs/privacy), `metadata` and [`routing`](https://infro.io/docs/features/routing) (whose `policy` is accepted and ignored) — are top-level body fields the OpenAI SDK types don't know about. In Python, pass them with `extra_body`; in Node, add them to the request params and silence the type error with `// @ts-expect-error` — the SDK forwards unknown fields as-is.

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.infro.io/v1",
    api_key=os.environ["INFRO_API_KEY"],
)

response = client.chat.completions.create(
    model="openai/gpt-5.6-sol",
    messages=[{"role": "user", "content": "Hello"}],
    extra_body={
        "fallbacks": ["anthropic/claude-sonnet-5"],
        "metadata": {"feature": "support-chat"},
    },
)
print(response.model)  # the model that actually served — matters with fallbacks
print(response.model_extra["provider"], response.model_extra["connection"])
```

## LangChain

LangChain fits when you're composing chains, agents, or retrieval pipelines and want models swappable behind one interface. Use `ChatOpenAI` from the `langchain-openai` package with a custom `base_url`.

```python
import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="openai/gpt-5.6-luna",
    base_url="https://api.infro.io/v1",
    api_key=os.environ["INFRO_API_KEY"],
)

print(llm.invoke("Hello").content)
```

## Vercel AI SDK

The Vercel AI SDK fits streaming chat UIs in Next.js and React — `streamText` and the `useChat` hook handle the SSE plumbing and UI state. Create a provider with `createOpenAI` from `@ai-sdk/openai` and reference models through `.chat()` — the provider's bare callable targets OpenAI's Responses API, which INFRO does not serve.

```typescript
import { createOpenAI } from "@ai-sdk/openai";
import { streamText } from "ai";

const infro = createOpenAI({
  baseURL: "https://api.infro.io/v1",
  apiKey: process.env.INFRO_API_KEY,
});

const result = streamText({
  model: infro.chat("google/gemini-3.1-pro"),
  prompt: "Explain SSE in one paragraph.",
});

for await (const text of result.textStream) process.stdout.write(text);
```

## LlamaIndex

LlamaIndex fits RAG applications where the framework manages ingestion, indexing, and retrieval over your own data. Install `llama-index-llms-openai-like` and set `api_base`.

```python
import os
from llama_index.llms.openai_like import OpenAILike

llm = OpenAILike(
    model="deepseek/deepseek-v4-flash",
    api_base="https://api.infro.io/v1",
    api_key=os.environ["INFRO_API_KEY"],
    is_chat_model=True,
)

print(llm.complete("Hello"))
```

> **Note:** Keep `is_chat_model=True`. INFRO only serves `/v1/chat/completions` — the legacy text-completions endpoint is not supported, and `OpenAILike` falls back to it when the flag is off.

## LiteLLM

LiteLLM fits when it is already your abstraction layer across providers, or when you run its proxy in front of application code. The `openai/` prefix tells LiteLLM to speak the OpenAI protocol to a custom `api_base`; everything after the prefix is the INFRO model ID.

```python
import os
import litellm

response = litellm.completion(
    model="openai/moonshot/kimi-k2.6",
    api_base="https://api.infro.io/v1",
    api_key=os.environ["INFRO_API_KEY"],
    messages=[{"role": "user", "content": "Hello"}],
)

print(response.choices[0].message.content)
```

## Other OpenAI-compatible tools

Any tool with a configurable OpenAI base URL — desktop chat clients, coding agents, evaluation harnesses, no-code builders — works the same way: base URL `https://api.infro.io/v1`, key in the `Authorization: Bearer` header. Streaming is standard OpenAI SSE (see [Streaming](https://infro.io/docs/api/streaming)) and failures follow the OpenAI error shape (see [Errors](https://infro.io/docs/api/errors)), so existing retry and parsing logic carries over.

The [quickstart](https://infro.io/docs/quickstart) covers creating a key and making a first request with plain `curl`; the [chat completions reference](https://infro.io/docs/api/chat-completions) documents every request and response field, including INFRO extensions.
