Integração de pagamento Pydantic AI.
Não há pacote Pydantic AI, e você não precisa de um. Registre uma função tipada com @agent.tool_plain, chame o cliente blockchain0x real, e seu agente pode mover USDC na Base.
Não existe um pacote específico para Pydantic AI, e você não precisa de um. O Pydantic AI transforma uma função em uma tool validada com , então você encapsula o cliente Python real em uma função tipada e o agente pode enviar USDC, liquidar invoices e ler wallets. Isso funciona com OpenAI, Anthropic, Google, Mistral, Groq e qualquer outro provider do Pydantic AI, porque a tool chama a HTTP API, não o modelo. Os pagamentos são liquidados na Base.
A tipagem do Pydantic AI vence. Use-a também para pagamentos.
O ponto principal do Pydantic AI é a tipagem forte: as entradas do agente são tipadas, as saídas são tipadas, as dependências são tipadas, as tentativas são tipadas. O framework rejeita dados malformados na fronteira em vez de permitir que se propaguem através da chamada do LLM. Sua ferramenta de carteira se baseia exatamente nisso - declare os argumentos com tipos, e o Pydantic AI constrói um esquema validado a partir da assinatura e da docstring antes que o modelo seja permitido chamá-lo.
O benefício prático: se o modelo tentar chamar send_usdc com um float em vez de uma string de unidade base, a falha ocorre na camada de validação do Pydantic antes de qualquer chamada HTTP para nós. Você vê um ValidationError claro com uma mensagem útil em vez de um 422 da API com caminhos de campo crípticos. Essa é a razão principal para envolver o cliente você mesmo aqui em vez de usar um adaptador genérico - você mantém a tipagem até o fio.
Instale Pydantic AI e o SDK principal. Duas chaves.
Não há pacote blockchain0x Pydantic AI para adicionar. Você instala Pydantic AI (Python 3.10+) e o SDK principal blockchain0x real, e então escreve a função abaixo. Essa é toda a lista de dependências.
pip install pydantic-ai blockchain0xexport OPENAI_API_KEY=sk-... export BLOCKCHAIN0X_API_KEY=sk_test_... # sk_test_ = Base Sepolia, sk_live_ = Base mainnet
OPENAI_API_KEY (ou o equivalente para qualquer provider que você use). BLOCKCHAIN0X_API_KEY é uma chave sk_test_ de testnet ou sk_live_ de mainnet do seu dashboard; o cliente a lê do ambiente. Se o seu agente também receber dinheiro, o handler de webhook também precisa de BLOCKCHAIN0X_WEBHOOK_SECRET.
Uma função tipada que paga, registrada como uma ferramenta.
Abaixo está toda a integração. send_usdc chama o cliente real blockchain0x; @agent.tool_plain o registra com um esquema construído a partir das dicas de tipo e da docstring. Execute-o e o agente move USDC no Base, com os argumentos validados antes da chamada.
from pydantic_ai import Agent from blockchain0x import Client blockchain0x = Client() # reads BLOCKCHAIN0X_API_KEY from the environment agent = Agent( "openai:gpt-4o", system_prompt="You pay vendor invoices in USDC within owner-set limits.", ) # Register a plain function as a tool. No dedicated package needed. @agent.tool_plain def send_usdc(agent_id: str, to: str, amount_wei: str) -> str: """Send a USDC payment from an agent wallet. amount_wei is USDC base units (6 decimals), so "10000" is 0.01 USDC. """ return str( blockchain0x.payments.create(body={"agentId": agent_id, "to": to, "amountWei": amount_wei}) ) result = agent.run_sync( "Pay 0.01 USDC from agent agt_123 to 0xVendor for the dataset." ) print(result.output)
When the agent decides to pay, it calls send_usdc, the SDK submits the transfer, and you get a transaction hash back. amount_wei is base units, so 0.01 USDC is "10000". A sk_test_ key keeps it on Base Sepolia until you switch to sk_live_. Want a typed result object instead of a string? Set the agent's output_type to your own Pydantic model and return it from the tool. Add read and settle functions the same way.
Confirme pagamentos recebidos com um webhook assinado.
Se seu agente também recebe USDC, confirme com o webhook em vez de polling. O helper de verificação é enviado no SDK Node; em um serviço Python você verifica manualmente contra o HMAC documentado. Se você quiser eventos tipados, defina seu próprio modelo Pydantic e model_validate_json o corpo bruto após a verificação da assinatura - a tipagem é sua para adicionar. Exemplo FastAPI abaixo.
import hmac, hashlib, os, time from fastapi import FastAPI, Request, HTTPException app = FastAPI() SECRET = os.environ["BLOCKCHAIN0X_WEBHOOK_SECRET"].encode() @app.post("/webhooks/payment") async def receive(request: Request): raw = await request.body() # RAW bytes - do not parse first sig = request.headers.get("X-Blockchain0x-Signature", "") ts = request.headers.get("X-Blockchain0x-Timestamp", "") parts = dict(p.split("=", 1) for p in sig.split(",") if "=" in p) t, v1 = parts.get("t", ts), parts.get("v1", sig) want = hmac.new(SECRET, t.encode() + b"." + raw, hashlib.sha256).hexdigest() if not hmac.compare_digest(want, v1) or abs(time.time() - int(t)) > 300: raise HTTPException(status_code=401) if request.headers.get("X-Blockchain0x-Event-Type") == "payment.received": await trigger_followup() # USDC landed - run the next step return {"ok": True}
O algoritmo é HMAC-SHA256 sobre a string t.rawBody, uma comparação em tempo constante e uma janela de replay de 300 segundos. Leia o corpo bruto via await request.body(), nunca request.json() re-serialized, porque isso altera os bytes que a assinatura cobre. Os eventos enviados são payment.received, payment.sent, wallet.deployed e webhook.test; estreite no cabeçalho X-Blockchain0x-Event-Type para ramificar.
O cliente que você está envolvendo é aberto. Leia-o.
Não existe um starter package do Pydantic AI para clonar - a receita acima é a integração. Os SDKs da blockchain0x são open source no GitHub; esta receita encapsula o Python SDK (blockchain0x-python), com a superfície completa de métodos na documentação. Leia como referência para os corpos das funções.
github.com/tosh-labs/blockchain0x-pythonA superfície completa de métodos e os escopos do SDK estão documentados em the docs. Comece com uma chave sk_test_ na Base Sepolia e depois mude para sk_live_ quando a função fizer o que você espera.
Cinco armadilhas específicas do Pydantic AI a evitar.
A forte tipagem do Pydantic AI captura a maioria dos bugs de integração na fronteira; estes são os poucos que escapam.
Não há pacote Pydantic AI - você registra uma ferramenta
Blockchain0x envia adaptadores para LangChain e CrewAI, além do servidor MCP; não há um pacote dedicado do Pydantic AI. A receita acima é o caminho: uma função tipada simples decorada com @agent.tool_plain que chama o cliente real do blockchain0x. O Pydantic AI lê a assinatura e a docstring para construir um esquema de ferramenta validado, que é exatamente a vitória de tipagem pela qual você veio ao Pydantic AI.
Mantenha o valor como uma string; deixe o Pydantic manter a linha.
payments.create takes amountWei: a string of USDC base units (6 decimals), so 0.01 USDC is "10000" and 5 USDC is "5000000". Type the tool argument as str and Pydantic AI rejects a float at the boundary with a clear ValidationError, before any HTTP call. That is the whole point of doing this in Pydantic AI - the malformed value never reaches the API.
send_payment pode responder 503 logo no início
payments.create não tenta novamente por padrão e pode retornar 503 até que o adaptador de cadeia esteja configurado para sua rede. Capture o erro dentro da sua ferramenta e retorne uma mensagem clara que o modelo possa agir, em vez de deixar o agente em loop. A chave de idempotência criada automaticamente significa que uma nova tentativa manual não resultará em pagamento duplicado.
Strings de modelo com prefixo de provedor
Pydantic AI usa strings de modelo com prefixo de provedor: 'openai:gpt-4o', 'anthropic:claude-3-5-sonnet-latest', 'google-gla:gemini-1.5-pro'. Omitir o prefixo gera um erro críptico de 'modelo desconhecido'. Sua ferramenta é agnóstica em relação ao provedor porque chama a API HTTP, não o modelo - troque o prefixo livremente e a função da carteira permanece inalterada.
tool_plain vs tool (RunContext)
Use @agent.tool_plain quando a função não precisar de nada da execução, como acima. Se você quiser as dependências do agente dentro da ferramenta (um id de cliente por solicitação, um limite de gasto), use @agent.tool e declare o primeiro argumento como ctx: RunContext[Deps] para ler ctx.deps. Misturar os dois - declarar um argumento ctx em tool_plain - gera um TypeError no registro.