Comment ajouter des paiements à votre agent IA.
Créez un agent avec createClient de @blockchain0x/node (ou le client Python), envoyez un paiement USDC avec payments.create, et vérifiez le webhook signé avec webhooks.verify. Les contrôles de dépenses sont définis dans le tableau de bord et en lecture seule via l'API. L'agent ne touche jamais directement aux clés privées. Moins de dix minutes de l'inscription à votre premier paiement USDC sur Base, en TypeScript ou Python.
Avant de commencer.
- Un compte Blockchain0x (inscription gratuite).
- Une clé API depuis le tableau de bord (utilisez une clé
sk_test_pour ce guide ; vous passerez àsk_live_plus tard). - Node.js 20+ ou Python 3.11+ dans votre environnement d'agent.
- Un agent construit sur n'importe quel framework - LangChain, CrewAI, AutoGen, LlamaIndex, OpenAI Agents SDK, MCP, ou code SDK standard. Les instructions sont indépendantes du framework.
- Un point de terminaison HTTPS accessible depuis Internet public pour recevoir des webhooks (ngrok ou un aperçu de déploiement est suffisant pour le développement).
Créer le profil de l'agent.
Le profil de l'agent est l'identité adressable derrière chaque paiement que votre agent envoie ou reçoit. Il contient l'adresse du portefeuille, la page publique, les badges de vérification et (plus tard) la politique de dépenses. Créez-en un par agent logique.
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.
Envoyez un paiement.
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 transferGérez le webhook.
Les webhooks sont comment vous découvrez qu'un paiement est réglé. Dans Node, webhooks.verify de @blockchain0x/node effectue la vérification HMAC et renvoie une union discriminée ; dans d'autres langages, calculez le même HMAC sur le corps brut. Branchez-vous sur le type d'événement (payment.received pour les entrées), répondez rapidement 2xx et mettez en file d'attente tout ce qui est plus lourd derrière le 2xx afin que la livraison ne dépasse pas le délai.
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)Définissez des contrôles de dépenses dans le tableau de bord.
Si votre agent ne fait que recevoir, vous pouvez ignorer cela. S'il paie également, définissez une autorisation de dépense - une allocation par période et un plafond par transaction - dans le tableau de bord. Cela est appliqué par le backend sur chaque paiement, donc cela survit à l'injection de prompt d'une manière que les règles côté agent ne peuvent jamais faire. Il n'y a pas d'appel API ou SDK qui modifie une autorisation (la clé de l'agent ne peut pas élargir sa limite) ; l'API est en lecture seule, donc votre code peut récupérer les valeurs actuelles à afficher ou à planifier.
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
}Testez l'ensemble du flux sur Base Sepolia.
Avant de passer aux clés sk_live_, exécutez le chemin complet de bout en bout avec sk_test_. Une clé de test garde tout sur Base Sepolia, où vous financez le portefeuille depuis le robinet public et les formes de réponse correspondent à la version en direct. Le préfixe de clé choisit le réseau, donc une clé de test ne peut pas déplacer des fonds du mainnet.
Exercez trois scénarios : un paiement sur la bonne voie qui déclenche payment.received, une livraison manquée (pointez le webhook vers une URL morte, puis réconciliez en récupérant la transaction avec transactions.get), et une nouvelle tentative de webhook (retournez un 500 la première fois, 200 la seconde, et confirmez que votre gestionnaire est idempotent). Lorsque les trois réussissent au test, échangez la clé et expédiez.
Cinq erreurs qui coûtent une semaine aux équipes.
Ignorer la vérification de la signature du webhook
Si vous acceptez tout POST à /webhooks/payment comme autoritaire, un attaquant peut créer de faux événements de paiement et tromper votre agent pour qu'il livre du travail gratuitement. Vérifiez toujours avec HMAC le secret du webhook, en utilisant une comparaison en temps constant. Le premier compromis est presque toujours la vérification manquante.
En supposant un événement de confirmation séparé
Les événements expédiés sont payment.received, payment.sent, wallet.deployed et webhook.test - il n'y a pas d'événement de confirmation séparé. payment.received se déclenche lorsque le transfert est dans un bloc. Pour la plupart des travaux, c'est votre signal pour livrer. Pour quelque chose de coûteux ou irréversible, interrogez la transaction avec transactions.get et appliquez votre propre seuil de confirmation avant d'agir ; ne pas attendre un événement qui n'existe pas.
Pas d'idempotence sur les gestionnaires de webhook
Les webhooks réessaient sur des réponses non-2xx, et le même événement arrivera plusieurs fois sous charge. Votre gestionnaire doit être idempotent : gardez une petite table des ID d'événements que vous avez déjà traités et ignorez les doublons. Sinon, un blip transitoire livrera le même travail deux fois et vous passerez des heures à déboguer des double-exécutions.
Mélanger les clés API de test et en direct
Les clés de test (sk_test_) touchent le sandbox et utilisent Base Sepolia ; les clés en direct (sk_live_) touchent la production et utilisent le réseau principal de Base. Les mélanger dans les configurations d'environnement est la cause de la plupart des tickets 'fonctionne en dev, échoue en prod'. Échec critique au démarrage si votre environnement d'exécution et le préfixe de clé ne correspondent pas.
Traiter un webhook manquant comme un paiement échoué
Il n'y a pas d'événement d'échec, et un webhook peut être manqué (votre point de terminaison était hors ligne, une livraison a été perdue). Ne laissez pas l'agent bloqué dans une boucle 'en attente de fonds'. Réconciliez : récupérez la transaction avec transactions.get pour connaître l'état réel, et mettez un délai sur tout flux d'attente afin qu'un paiement abandonné libère les ressources retenues au lieu de rester bloqué indéfiniment.
Une fois que vous avez votre premier paiement.
Avec des paiements de base fonctionnant, les suivis les plus rentables sont les contrôles de dépenses (pour que l'agent ne puisse pas s'enfuir avec le budget), la robustesse des webhooks (pour que les paiements ne tombent pas silencieusement sous charge) et la vérification d'identité (pour que les contreparties fassent confiance à la page publique de l'agent).
Mettre en place des contrôles de dépenses d'agent qui survivent à l'injection d'invite
Les modèles de webhook dont les développeurs parlent le plus
Gagnez les badges de vérification GitHub et domaine
La référence API complète se trouve à docs.blockchain0x.com. Surface produit pour les mêmes API : API de paiement.