Intégration de paiement LangGraph.
Aucun package LangGraph nécessaire. Un nœud simple appelle le véritable client blockchain0x, interrupt() suspend jusqu'à ce que le webhook de paiement arrive, et le graphe reprend - durable à travers les exécutions.
Il n'existe pas de package LangGraph, et vous n'en avez pas besoin. Un simple nœud dans votre appelle le vrai client , un suspend le graphe jusqu'à l'arrivée du webhook de paiement, et le handler le reprend avec les propres + de LangGraph. Les paiements sont réglés sur Base.
L'exécution durable rend le modèle de reprise après paiement naturel.
La partie difficile des paiements pilotés par des agents est le décalage asynchrone : vous demandez un paiement, l'acheteur paie quelques minutes plus tard (ou jamais), et vous devez reprendre le travail sans perdre l'état de là où vous en étiez. La plupart des frameworks d'agents s'appuient sur une file d'attente de tâches + un magasin d'état manuel pour combler ce fossé. LangGraph a déjà la primitive intégrée : interrupt() suspend un graphique à un nœud et un point de contrôle persiste l'état sur le disque. Reprendre est un appel.
La recette s'appuie sur cela sans machinerie spéciale. Un nœud de paiement simple appelle blockchain0x.payments.create. Un nœud await_settlement appelle interrupt() pour suspendre, et le vérificateur persiste l'état. Le gestionnaire de webhook vérifie la signature, définit le statut sur 'settled' dans le fil correspondant avec graph.updateState, et appelle graph.invoke pour continuer à partir de l'interruption. Le graphique reprend exactement là où il s'était arrêté, y compris tout contexte LLM des nœuds précédents - le tout en utilisant les propres API de LangGraph.
Installez LangGraph et le SDK de base. Aucun package supplémentaire.
Node 18+ et @langchain/langgraph 0.2+ plus le véritable client @blockchain0x/node. Il n'y a pas d'adaptateur LangGraph à ajouter dans l'un ou l'autre langage - les utilisateurs de LangGraph Python installent langgraph et le client Python blockchain0x et écrivent la même recette, avec interrupt() et Command(resume=...) du côté Python.
npm install @langchain/langgraph @blockchain0x/node
export BLOCKCHAIN0X_API_KEY=sk_test_... # sk_test_ = Base Sepolia, sk_live_ = Base mainnet export BLOCKCHAIN0X_WEBHOOK_SECRET=... # for the webhook handler
BLOCKCHAIN0X_API_KEY est une clé sk_test_ testnet ou sk_live_ mainnet de votre tableau de bord ; le client la lit depuis l'environnement. BLOCKCHAIN0X_WEBHOOK_SECRET (renvoyé une fois lorsque vous créez ou faites tourner un webhook) est nécessaire dans le processus qui gère les webhooks. Si votre graphe s'exécute dans un processus et le gestionnaire dans un autre, les deux ont besoin du même point de contrôle (par exemple, Postgres partagé) afin que le gestionnaire puisse trouver le fil suspendu.
Un graphique à trois nœuds : payer, suspendre, livrer.
Ci-dessous se trouve un flux de travail LangGraph complet avec un état typé, un nœud de paiement qui appelle le véritable blockchain0x.payments.create, un nœud await_settlement basé sur des interruptions, et un nœud de livraison qui exécute le travail dépendant une fois que la chaîne confirme que le paiement a été effectué.
import { StateGraph, START, END, MemorySaver, interrupt, Annotation } from "@langchain/langgraph"; import { createClient } from "@blockchain0x/node"; const blockchain0x = createClient({ apiKey: process.env.BLOCKCHAIN0X_API_KEY! }); const State = Annotation.Root({ agentId: Annotation<string>(), to: Annotation<string>(), amountWei: Annotation<string>(), // USDC base units: "10000" = 0.01 USDC settled: Annotation<boolean>(), }); // A plain node that calls the real SDK. No dedicated package needed. async function pay(state: typeof State.State) { await blockchain0x.payments.create({ agentId: state.agentId, to: state.to, amountWei: state.amountWei, }); return {}; } // Suspend the graph until the payment.sent webhook resumes this thread. function awaitSettlement() { interrupt("awaiting on-chain settlement"); return {}; } async function deliver() { // Funds have moved - do the work that depended on the payment. return {}; } const graph = new StateGraph(State) .addNode("pay", pay) .addNode("await_settlement", awaitSettlement) .addNode("deliver", deliver) .addEdge(START, "pay") .addEdge("pay", "await_settlement") .addConditionalEdges("await_settlement", (s) => (s.settled ? "deliver" : END)) .addEdge("deliver", END) .compile({ checkpointer: new MemorySaver() });
When the graph runs, the pay node submits the USDC transfer through the SDK. The await_settlement node calls interrupt(), which suspends the graph and persists state via the checkpointer. The conditional edge waits to be told settled=true before routing to deliver; if settlement never lands, a timeout sweep routes it to END. amountWei is base units, so 0.01 USDC is "10000".
Vérifiez le webhook, puis reprenez le fil.
Le gestionnaire vérifie la signature avec webhooks.verify du SDK Node, recherche le fil LangGraph suspendu dans votre propre mappage, définit settled avec graph.updateState, et appelle graph.invoke(null, config) pour continuer à partir de l'interruption. Pas d'aide spéciale - ce sont les propres API de LangGraph.
import express from "express"; import { webhooks } from "@blockchain0x/node"; import { graph } from "./graph"; 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", async (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.sent") { // You map the event to the suspended graph thread (your own store). const config = { configurable: { thread_id: threadFor(result.eventId) } }; await graph.updateState(config, { settled: true }); await graph.invoke(null, config); // resume from the interrupt } res.status(200).send("ok"); });
webhooks.verify effectue HMAC-SHA256 en temps constant sur le corps brut et renvoie une union discriminée - branchez sur result.ok, pas de try/catch. Mappez result.eventId au thread que vous avez suspendu, puis graph.updateState + graph.invoke(null, config) reprend à partir du point de contrôle persistant et le graphique exécute les livraisons. Les événements expédiés sont payment.received, payment.sent, wallet.deployed et webhook.test.
Le client que vous enveloppez est ouvert. Lisez-le.
Il n'y a pas de package de démarrage LangGraph à cloner - la recette ci-dessus est l'intégration. Les SDK blockchain0x sont open source sur GitHub ; cette recette encapsule le SDK Python (blockchain0x-python), avec la surface complète des méthodes dans la documentation. Lisez-le pour une référence sur les corps de nœuds et la vérification du webhook.
github.com/tosh-labs/blockchain0x-pythonLa surface complète des méthodes SDK et le schéma de signature du webhook sont documentés dans la documentation. Commencez avec une clé sk_test_ sur Base Sepolia, puis passez à sk_live_ une fois que le graphique reprend comme vous l'attendez.
Cinq pièges spécifiques à LangGraph à éviter.
Le modèle d'exécution durable de LangGraph est puissant mais a ses propres pièges autour des points de contrôle, des interruptions et des mises à jour d'état.
Il n'y a pas de package LangGraph - un nœud simple appelle le SDK
Blockchain0x expédie des adaptateurs pour LangChain et CrewAI ainsi que le serveur MCP ; il n'y a pas de package LangGraph dédié, dans npm ou pip. La recette ci-dessus est le chemin : un nœud de graphe ordinaire appelle le véritable client @blockchain0x/node, et vous reprenez avec graph.updateState + graph.invoke de LangGraph. Il n'y a pas de classe de nœud de paiement spéciale et pas d'assistant de reprise à importer - ceux-ci n'ont jamais existé.
Checkpointer manquant
L'interrupt() de LangGraph ne fonctionne que si le graphique a un point de contrôle. Sans lui, l'état s'évapore lorsque votre processus se termine et le gestionnaire de webhook n'a pas de fil à reprendre. Utilisez MemorySaver pour le développement et SqliteSaver ou PostgresSaver en production. Si votre graphique et votre gestionnaire de webhook s'exécutent dans des processus différents, ils doivent partager le même point de contrôle (par exemple, un Postgres) afin que le gestionnaire puisse trouver le fil suspendu.
Mapper le webhook au bon fil est votre travail
Le webhook vous informe qu'un paiement a été réglé ; il ne connaît pas votre LangGraph thread_id. Gardez votre propre mappage - lorsque vous démarrez un graphique, stockez thread_id indexé par l'agent, le destinataire, ou une clé d'idempotence que vous définissez, puis recherchez-le dans le gestionnaire. L'appel threadFor() ci-dessus est cette recherche. Si vous vous trompez, graph.invoke reprend le mauvais fil ou aucun.
Gérez le chemin sans règlement, ou suspendez pour toujours
Le bord conditionnel de await_settlement achemine la livraison uniquement lorsque settled est vrai. Si un paiement n'atterrit jamais, le fil reste suspendu indéfiniment. Ajoutez un délai d'attente : un balayage programmé qui reprend les fils périmés avec settled=false afin que le bord achemine vers END, ou un contrôle payment.sent-versus-deadline. Un fil suspendu ne coûte rien, mais il ne se termine jamais par lui-même.
Les montants sont des unités de base USDC, sous forme de chaînes
payments.create takes amountWei: a string of USDC base units (6 decimals), so 0.01 USDC is "10000" and 5 USDC is "5000000". It also does not retry by default and can answer 503 until the chain adapter is wired for your network. Handle that in the pay node - route to END or a retry node on error rather than letting the graph wedge.