# Connect Pydantic AI to Router One with an explicit chat model

> Markdown mirror of https://router.one/integrations/pydantic-ai for AI assistants and crawlers. Router One is an OpenAI-compatible LLM API gateway.
> Last updated: 2026-09-05

Pydantic AI builds Python agents with typed results and application tools. Use Router One as its model provider while Pydantic AI manages the agent loop, validation, tools, and message history in your application. This guide starts with a plain-text Chat Completions call, then explains what changes when you add structured output or multiple model requests.

## Install the OpenAI integration and set your credentials

Use Python 3.10 or newer. In that environment, install pydantic-ai-slim with the openai extra; the full pydantic-ai package also includes this integration. The shell example below is for macOS/Linux. Replace both placeholders before running it, using a Router One key and the exact ID of a current model that supports Chat Completions. These ROUTER_ONE_* variable names belong to the example, which reads them explicitly. Keep the same environment active when running the Python file.

`terminal`

```bash
python -m pip install "pydantic-ai-slim[openai]"
export ROUTER_ONE_API_KEY="sk-your-router-one-key"
export ROUTER_ONE_MODEL_ID="<exact-model-id-from-/models>"
```

## Configure Pydantic AI to use the Router One base URL

Save this as pydantic_ai_router_one.py and run python pydantic_ai_router_one.py. OpenAIChatModel selects /v1/chat/completions explicitly; OpenAIProvider receives the /v1 base URL and your key. The catalog model ID is passed unchanged, including any provider prefix that is part of the ID. output_type=str requests plain text so the first check does not depend on tools or JSON-schema output. request_limit=3 bounds model requests tracked by Pydantic AI for this run.

`pydantic_ai_router_one.py`

```python
import os

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.openai import OpenAIProvider
from pydantic_ai.usage import UsageLimits

model = OpenAIChatModel(
    os.environ["ROUTER_ONE_MODEL_ID"],
    provider=OpenAIProvider(
        base_url="https://api.router.one/v1",
        api_key=os.environ["ROUTER_ONE_API_KEY"],
    ),
)
agent = Agent(model, output_type=str)
result = agent.run_sync(
    "Reply with one short greeting.",
    usage_limits=UsageLimits(request_limit=3),
)
print(result.output)
```

## Choose a typed-output mode after text works

For typed results, define your schema as a pydantic.BaseModel and choose an output mode. Import ToolOutput, NativeOutput, or PromptedOutput from pydantic_ai when using a wrapper below; MySchema stands for your own model class. A Python type declaration alone does not establish what the upstream model supports. Pydantic validates returned data in your application, and validation retries can make additional model requests.

| Agent output_type | How it works | What to verify |
| --- | --- | --- |
| str | Plain model text, as in the example | A successful Chat Completions request |
| MySchema or ToolOutput(MySchema) | Uses an output tool; this is the default for a schema type | Function/tool calling on the selected model and endpoint |
| NativeOutput(MySchema) | Uses the model's native JSON-schema response format | Native structured-output support and the accepted schema constraints |
| PromptedOutput(MySchema) | Adds the schema to the prompt, then parses and validates the result | The model may still return invalid data; prompts do not enforce the schema |

## Budget the agent run and reconcile its model calls

One agent run can contain multiple model requests as tools execute or output validation retries. UsageLimits(request_limit=3) is an application-side request limit, not a three-request billing guarantee or a currency budget: SDK HTTP retries and gateway provider retries are separate mechanisms. Give the application a dedicated Router One key with maxSpend. Match requests in Dashboard → Logs by that key, time, exact model, and request_id, and use the gateway's recorded charges to reconcile the run. An agent-level usage or cost estimate need not match your Router One rate. Router One records model-call metadata; it does not execute your Python tools or provide Pydantic AI's agent state and storage.

## Which model ID should Pydantic AI send?

Copy the exact model ID from /models, preserving case, hyphens, and version suffixes; do not substitute a display name. Open its detail page and match the supported API endpoints, context window, and capabilities such as tool calling to the provider and features selected in Pydantic AI. A catalog listing does not mean the client can use every feature of that model. Give each tool a dedicated API key with a maxSpend cap.

## Which API protocol is Pydantic AI using?

OpenAI-compatible describes an interface format; it does not make Chat Completions (/v1/chat/completions), Responses (/v1/responses), and Anthropic Messages (/v1/messages) interchangeable. Check the installed client version, provider configuration, and actual request path against the model detail page and API compatibility fact sheet. A successful plain-text chat does not establish support for hosted tools, conversation state, or file-editing features.

## Verify the Pydantic AI call in your request trace

Send a simple text request from Pydantic AI, then match its trace in Dashboard → Logs by time, model, and request_id: tokens, cost, latency, and status. Next, test streaming, tool calls, and multi-turn history separately. For failures, retain the actual request path, full error message, and request_id. If there is no matching log, check client configuration and connectivity before attributing the error to the gateway or upstream.

## FAQ

### Why use OpenAIChatModel instead of Agent('openai:...')?

Current Pydantic AI documentation maps the bare openai: prefix to OpenAIResponsesModel. This guide constructs OpenAIChatModel so it stays on Chat Completions regardless of shorthand defaults. If you intentionally choose OpenAIResponsesModel, check /v1/responses support for the model and every feature you enable; a successful chat request does not establish that compatibility.

### Text works, but typed output or an agent tool fails. What changes?

Check which output mode is active. Passing a BaseModel as output_type normally adds a tool schema, while NativeOutput uses a JSON-schema response format. Verify that capability for the exact model and endpoint, then inspect the full error and request_id. Tool schemas, strict-mode options, and model profiles can have provider-specific requirements; change them only to match the documented API behavior. Start again with output_type=str to isolate basic connectivity from output-mode support.

### How should I call the agent from an async server or notebook?

The example uses run_sync for a standalone Python script. Inside an active async event loop, use await agent.run(..., usage_limits=UsageLimits(request_limit=3)) and read result.output. Keep tool execution, history storage, and any framework instrumentation in your application; the Router One trace covers each gateway model request.

### Which models can Pydantic AI use through the gateway?

Choose a current catalog model that supports both the endpoint and the features Pydantic AI uses. Check /models and the model detail page for the exact ID, current rates, and capabilities; a family name such as GPT or Claude is not a compatibility guarantee. Seeing a model in the picker confirms discovery, so verify an actual request too.

### Models are listed, but requests fail with 400 or 404. What should I check?

Record the actual request path and error message, then check the exact model ID. A 400 can indicate invalid parameters, unsupported tools, or a model/endpoint mismatch; a 404 can indicate an incorrect path or missing resource, so it does not by itself establish that a model was retired. If the error says must be called via, use the named endpoint or select a model supported on the current endpoint. Do not add or remove /v1 or /chat/completions across all clients indiscriminately.

### Does this work from Mainland China?

Yes. The gateway is reachable from Mainland China without a VPN, and the configuration is identical to the global setup.

### How do I debug a 401/402/403/429?

Match the request and error message in Dashboard → Logs. For 401, check whether the key was sent and is valid; for 402, check wallet balance and maxSpend; for 403, check key permissions and access restrictions. For 429, distinguish request/token limits from upstream throttling using the error details. Keep the request_id and follow the error-codes reference.

## See also

- All integration guides: https://router.one/integrations
- Debug API errors in Pydantic AI: https://router.one/llm-api-error-codes
- API compatibility: endpoints and supported features: https://router.one/facts/api-compatibility.md
- Responses API setup and limits: https://router.one/codex-responses-api
- Cline setup: https://router.one/integrations/cline
- Aider setup: https://router.one/integrations/aider
- OpenAI Python SDK setup: https://router.one/integrations/openai-sdk
- Structured-output API requirements: https://router.one/llm-structured-outputs
- Per-key model cost tracking: https://router.one/llm-cost-tracking
- Pydantic AI: OpenAI-compatible providers: https://pydantic.dev/docs/ai/models/openai/
- Pydantic AI: output modes: https://pydantic.dev/docs/ai/core-concepts/output/
- Pydantic AI: UsageLimits reference: https://pydantic.dev/docs/ai/api/pydantic-ai/usage/
- What the gateway layer does: https://router.one/llm-api-gateway
- OpenAI-compatible API: https://router.one/openai-compatible-api
- API docs: https://router.one/docs
- Canonical page: https://router.one/integrations/pydantic-ai
- Models and per-model token rates: https://router.one/models (markdown: https://router.one/models.md)
- Pricing: https://router.one/pricing
- API docs (markdown): https://router.one/docs.md
- Company facts: https://router.one/facts/company.md
