Como adicionar pagamentos ao seu agente de IA.
Crie um agente com createClient de @blockchain0x/node (ou o cliente Python), envie um pagamento USDC com payments.create e verifique o webhook assinado com webhooks.verify. Os controles de gastos são definidos no painel e são somente leitura pela API. O agente nunca toca nas chaves privadas diretamente. Menos de dez minutos do registro até o seu primeiro pagamento USDC no Base, em TypeScript ou Python.
Antes de você começar.
- Uma conta Blockchain0x (inscrição gratuita).
- Uma chave de API do painel (use uma chave
sk_test_para este guia; você mudará parask_live_mais tarde). - Node.js 20+ ou Python 3.11+ no seu tempo de execução de agente.
- Um agente construído em qualquer framework - LangChain, CrewAI, AutoGen, LlamaIndex, OpenAI Agents SDK, MCP ou código SDK simples. As instruções são independentes de framework.
- Um endpoint HTTPS acessível pela internet pública para receber webhooks (ngrok ou uma prévia de implantação é bom para desenvolvimento).
Crie o perfil do agente.
O perfil do agente é a identidade endereçável por trás de cada pagamento que seu agente envia ou recebe. Ele contém o endereço da carteira, a página pública, os distintivos de verificação e (mais tarde) a política de gastos. Crie um por agente lógico.
import { createClient } from "@blockchain0x/node";
const client = createClient({ apiKey: process.env.BLOCKCHAIN0X_API_KEY! }); // sk_test_ / sk_live_
const agent = await client.agents.create({ name: "research-bot" });
console.log(agent.id); // "agt_..."
// Public page: https://wallet.blockchain0x.com/a/{slug}from blockchain0x import Client
client = Client() # reads BLOCKCHAIN0X_API_KEY from the environment
agent = client.agents.create(body={"name": "research-bot"})
print(agent["id"]) # "agt_..."
# Public page: https://wallet.blockchain0x.com/a/{slug}After this call, the agent has a public page at https://wallet.blockchain0x.com/a/<slug> that any counterparty (human or agent) can hover for verification info. See the agent payment identity glossary entry for what that page exposes.
Envie um pagamento.
payments.create sends USDC from the agent wallet. amountWei is base units (USDC has 6 decimals), so 0.01 USDC is the string "10000". The SDK auto-stamps an Idempotency-Key, and the call can return 503 until the chain adapter is wired for your network. To RECEIVE instead, settle an invoice you created in the dashboard with paymentRequests.settle - see the payment API page.
// Send a USDC payment from the agent wallet. amountWei is base units
// (USDC has 6 decimals): "10000" is 0.01 USDC. payments.create auto-stamps an
// Idempotency-Key and can return 503 until the chain adapter is wired.
const tx = await client.payments.create({
agentId: agent.id,
to: "0xRecipient",
amountWei: "10000",
});
console.log(tx); // the submitted transfer# amountWei is USDC base units (6 decimals): "10000" is 0.01 USDC.
tx = client.payments.create(body={
"agentId": agent["id"],
"to": "0xRecipient",
"amountWei": "10000",
})
print(tx) # the submitted transferGerencie o webhook.
Webhooks são como você descobre que um pagamento foi liquidado. No Node, webhooks.verify de @blockchain0x/node faz a verificação HMAC e retorna uma união discriminada; em outras linguagens, calcule o mesmo HMAC sobre o corpo bruto. Faça ramificações com base no tipo de evento (payment.received para inbound), responda 2xx rapidamente e coloque qualquer coisa mais pesada atrás do 2xx para que a entrega não expire.
import express from "express";
import { webhooks } from "@blockchain0x/node";
const app = express();
// Capture the RAW body. The HMAC is over the exact bytes on the wire.
app.use(express.raw({ type: "application/json" }));
app.post("/webhooks/payment", (req, res) => {
const result = webhooks.verify({
headers: req.headers,
rawBody: req.body, // Buffer, raw bytes
secret: process.env.BLOCKCHAIN0X_WEBHOOK_SECRET!,
});
if (!result.ok) return res.status(400).json({ code: result.code });
if (result.eventType === "payment.received") {
// USDC landed - deliver the work, fulfil the order, etc.
void deliver(result.eventId);
}
res.status(200).send("ok");
});import hmac, hashlib, os, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["BLOCKCHAIN0X_WEBHOOK_SECRET"].encode()
@app.post("/webhooks/payment")
def webhook():
raw = request.get_data() # 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:
abort(401)
if request.headers.get("X-Blockchain0x-Event-Type") == "payment.received":
deliver(request.get_json()) # USDC landed
return ("ok", 200)Defina controles de gasto no painel.
Se seu agente apenas recebe, você pode pular isso. Se ele também paga, defina uma permissão de gasto - uma concessão por período e um limite por transação - no painel. É aplicada pelo backend em cada pagamento, então sobrevive à injeção de prompt de uma maneira que as regras do lado do agente nunca podem. Não há chamada de API ou SDK que mude uma permissão (a própria chave do agente não pode ampliar seu limite); a API é somente leitura, então seu código pode buscar os valores atuais para exibir ou planejar em torno.
curl https://api.blockchain0x.com/v1/agents/agt_123/spend-permissions \
-H "Authorization: Bearer $BLOCKCHAIN0X_API_KEY"{
"allowance_wei": "5000000",
"per_tx_wei": "1000000",
"period_seconds": 86400,
"revoked_at": null
}Teste todo o fluxo no Base Sepolia.
Antes de mudar para chaves sk_live_, execute todo o caminho de ponta a ponta com sk_test_. Uma chave de teste mantém tudo no Base Sepolia, onde você financia a carteira a partir da torneira pública e as formas de resposta correspondem ao vivo. O prefixo da chave escolhe a rede, então uma chave de teste não pode mover fundos da mainnet.
Exercite três cenários: um pagamento de caminho feliz que dispara payment.received, uma entrega perdida (apontar o webhook para uma URL morta, depois reconciliar buscando a transação com transactions.get), e uma nova tentativa de webhook (retornar um 500 na primeira vez, 200 na segunda, e confirmar que seu manipulador é idempotente). Quando os três passarem no teste, troque a chave e envie.
Cinco erros que custam uma semana às equipes.
Ignorando a verificação de assinatura do webhook
Se você aceitar qualquer POST para /webhooks/payment como autoritativo, um atacante pode criar eventos de pagamento falsos e enganar seu agente para entregar trabalho gratuitamente. Sempre verifique HMAC com o segredo do webhook, usando uma comparação de tempo constante. O primeiro compromisso é quase sempre a verificação ausente.
Assumindo um evento de confirmação separado
Os eventos enviados são payment.received, payment.sent, wallet.deployed e webhook.test - não há um evento de confirmação separado. payment.received é acionado quando a transferência está em um bloco. Para a maioria dos trabalhos, esse é seu sinal para entregar. Para algo caro ou irreversível, consulte a transação com transactions.get e aplique seu próprio limite de confirmação antes de agir; não espere por um evento que não existe.
Sem idempotência em manipuladores de webhook
Webhooks tentam novamente em respostas não-2xx, e o mesmo evento chegará várias vezes sob carga. Seu manipulador deve ser idempotente: mantenha uma pequena tabela de IDs de eventos que você já processou e pule duplicatas. Caso contrário, um pequeno erro transitório entregará o mesmo trabalho duas vezes e você gastará horas depurando duplicações.
Misturando chaves de API de teste e ao vivo
As chaves de teste (sk_test_) atingem o sandbox e usam o Base Sepolia; as chaves ao vivo (sk_live_) atingem a produção e usam o mainnet do Base. Misturá-las nas configurações de ambiente é a causa da maioria dos tickets 'funciona em dev, falha em prod'. Falha crítica na inicialização se seu ambiente de execução e o prefixo da chave não corresponderem.
Tratando um webhook ausente como um pagamento falhado
Não há evento de falha, e um webhook pode ser perdido (seu endpoint estava fora do ar, uma entrega foi descartada). Não deixe o agente preso em um loop de 'aguardando fundos'. Reconcile: busque a transação com transactions.get para aprender o estado real e coloque um tempo limite em qualquer fluxo de espera para que um pagamento abandonado libere recursos retidos em vez de ficar pendurado para sempre.
Uma vez que você tenha seu primeiro pagamento.
Com os pagamentos básicos funcionando, os seguimentos que mais compensam são controles de gastos (para que o agente não possa fugir com o orçamento), robustez de webhook (para que os pagamentos não caiam silenciosamente sob carga) e verificação de identidade (para que as contrapartes confiem na página pública do agente).
Configure controles de gastos do agente que sobrevivem à injeção de prompt
Os padrões de webhook que os desenvolvedores mais perguntam
Ganhe os badges de verificação do GitHub e do domínio
A referência completa da API está em docs.blockchain0x.com. Superfície de produto para as mesmas APIs: API de Pagamento.