How to Add ATXP to Pydantic AI

Pydantic AI produces some of the cleanest agent code in Python — type-safe, well-structured, easy to reason about. What it doesn’t address: the payment layer. Your agents call LLMs with your keys and have no spending ceiling.

ATXP adds that layer with minimal changes to your existing code.

What Changes (Minimally)

You change one thing: the LLM provider configuration. Instead of pointing Pydantic AI at OpenAI or Anthropic directly, you point it at ATXP’s proxy endpoint with an agent-specific key. The agent key is tied to an ATXP account with a real credit balance that ATXP enforces.

Everything else — structured outputs, tool calls, retry logic, validation — stays the same.

Prerequisites

  • Python 3.10+
  • pydantic-ai installed
  • An ATXP account (atxp.ai)

Step 1: Create an Agent Account

import httpx
import os

ATXP_API_KEY = os.environ["ATXP_API_KEY"]

with httpx.Client() as client:
    response = client.post(
        "https://api.atxp.ai/v1/agents",
        headers={"Authorization": f"Bearer {ATXP_API_KEY}"},
        json={
            "name": "pydantic-research-agent",
            "budget": 4.00,
            "currency": "usd",
        }
    )

agent_data = response.json()
agent_id = agent_data["id"]
agent_key = agent_data["api_key"]

Step 2: Configure Pydantic AI to Use ATXP

Pydantic AI uses OpenAI-compatible model providers. Configure the model to use ATXP’s proxy:

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel
from openai import AsyncOpenAI

# OpenAI client pointing at ATXP's proxy with the agent key
atxp_client = AsyncOpenAI(
    api_key=agent_key,
    base_url="https://api.atxp.ai/v1/proxy/openai",
)

model = OpenAIModel("gpt-4o", openai_client=atxp_client)

For Anthropic models:

from pydantic_ai.models.anthropic import AnthropicModel
import anthropic

atxp_anthropic = anthropic.AsyncAnthropic(
    api_key=agent_key,
    base_url="https://api.atxp.ai/v1/proxy/anthropic",
)

model = AnthropicModel("claude-sonnet-4-6", anthropic_client=atxp_anthropic)

Step 3: Define Your Agent Normally

from pydantic import BaseModel

class ResearchResult(BaseModel):
    summary: str
    key_findings: list[str]
    confidence: float

research_agent = Agent(
    model,
    result_type=ResearchResult,
    system_prompt=(
        "You are a research agent. Analyze the provided topic and return "
        "structured findings with a confidence score."
    ),
)

Step 4: Run It

import asyncio

async def main():
    result = await research_agent.run(
        "What are the current agent payment protocols and their tradeoffs?"
    )

    print(f"Summary: {result.data.summary}")
    print(f"Findings: {result.data.key_findings}")
    print(f"Confidence: {result.data.confidence:.0%}")

asyncio.run(main())

Step 5: Check Spend

async def check_agent_spend(agent_id: str) -> dict:
    async with httpx.AsyncClient() as client:
        txns = await client.get(
            f"https://api.atxp.ai/v1/agents/{agent_id}/transactions",
            headers={"Authorization": f"Bearer {ATXP_API_KEY}"}
        )
        balance = await client.get(
            f"https://api.atxp.ai/v1/agents/{agent_id}/balance",
            headers={"Authorization": f"Bearer {ATXP_API_KEY}"}
        )

    return {
        "transactions": txns.json()["data"],
        "balance": balance.json()["available_usd"]
    }

Handling Budget Depletion

When the agent’s ATXP account hits zero, the proxy returns a 402. Pydantic AI surfaces this as a ModelHTTPError. Handle it:

from pydantic_ai.exceptions import ModelHTTPError

async def run_with_budget_handling(query: str):
    try:
        result = await research_agent.run(query)
        return result.data
    except ModelHTTPError as e:
        if e.status_code == 402:
            # Agent is out of credits
            raise BudgetExhaustedError(
                f"Agent {agent_id} exhausted its budget. Refill at atxp.ai."
            )
        raise

Multi-Tenant Pattern

For applications where multiple users run the same agent type, create one ATXP account per user session:

async def create_user_agent(user_id: str, budget_usd: float):
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.atxp.ai/v1/agents",
            headers={"Authorization": f"Bearer {ATXP_API_KEY}"},
            json={
                "name": f"user-{user_id}-agent",
                "budget": budget_usd,
                "metadata": {"user_id": user_id},
            }
        )

    agent_data = response.json()

    # Configure Pydantic AI model for this user's agent
    atxp_client = AsyncOpenAI(
        api_key=agent_data["api_key"],
        base_url="https://api.atxp.ai/v1/proxy/openai",
    )

    return Agent(
        OpenAIModel("gpt-4o", openai_client=atxp_client),
        result_type=ResearchResult,
        system_prompt="...",
    )

Each user’s agent has an isolated key and a separate spending limit. You can attribute costs per user and prevent any single user from running up an outsized bill.

For the broader infrastructure pattern — how identity, payments, and permissions fit together for agent systems — see how to give an AI agent payments and identity.

Get started with ATXP.