Integrazione dei pagamenti LangGraph.
Nessun pacchetto LangGraph necessario. Un nodo semplice chiama il vero client blockchain0x, interrupt() sospende fino all'arrivo del webhook di pagamento, e il grafo riprende - durevole attraverso le esecuzioni.
Non esiste un package specifico per LangGraph, e non ne hai bisogno. Un semplice nodo nel tuo chiama il vero client , un sospende il grafo finché non arriva il webhook del pagamento, e l'handler lo riprende con i componenti nativi di LangGraph + . I pagamenti si regolano su Base.
L'esecuzione durevole rende naturale il modello di ripresa dopo il pagamento.
La parte difficile dei pagamenti guidati dagli agenti è il gap asincrono: richiedi un pagamento, l'acquirente paga minuti dopo (o mai), e devi riprendere il lavoro senza perdere lo stato di dove eri. La maggior parte dei framework per agenti si basa su una coda di lavoro + uno stato di archiviazione manuale per colmare questo gap. LangGraph ha già la primitiva integrata: interrupt() sospende un grafo in un nodo e un checkpointer persiste lo stato su disco. Riprendere è una chiamata.
La ricetta sfrutta questo senza alcun meccanismo speciale. Un semplice nodo pay chiama blockchain0x.payments.create. Un nodo await_settlement chiama interrupt() per sospendere, e il checkpointer persiste lo stato. L'handler del webhook verifica la firma, imposta settled nel thread corrispondente con graph.updateState e chiama graph.invoke per riprendere dall'interrupt. Il grafo riparte esattamente da dove si era fermato, incluso ogni contesto LLM dei nodi precedenti - tutto usando le API native di LangGraph.
Installa LangGraph e il core SDK. Nessun pacchetto extra.
Node 18+ e @langchain/langgraph 0.2+ più il vero client @blockchain0x/node. Non esiste un adattatore LangGraph da aggiungere in nessuna lingua - gli utenti di Python LangGraph installano langgraph e il client Python blockchain0x e scrivono la stessa ricetta, con interrupt() e Command(resume=...) sul lato 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 è una chiave sk_test_ per testnet o sk_live_ per mainnet dalla tua dashboard; il client la legge dall'ambiente. BLOCKCHAIN0X_WEBHOOK_SECRET (restituito una sola volta quando crei o ruoti un webhook) è necessario nel processo che gestisce i webhook. Se il tuo graph gira in un processo e il gestore in un altro, entrambi devono usare lo stesso checkpointer (ad esempio un Postgres condiviso) così il gestore può trovare il thread sospeso.
Un grafo a tre nodi: paga, sospendi, consegna.
Di seguito è riportato un workflow LangGraph completo con uno State tipizzato, un nodo pay che chiama il vero blockchain0x.payments.create, un nodo await_settlement basato su interrupt e un nodo deliver che esegue il lavoro dipendente una volta che la chain conferma lo spostamento del pagamento.
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".
Verifica il webhook, poi riprendi il thread.
Il gestore verifica la firma con webhooks.verify dal Node SDK, cerca il thread LangGraph sospeso dalla tua mappatura, imposta settled con graph.updateState e chiama graph.invoke(null, config) per continuare dall'interruzione. Nessun helper speciale - queste sono le API di 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 esegue HMAC-SHA256 in tempo costante sul corpo raw e restituisce un'unione discriminata - ramifica su result.ok, senza try/catch. Mappa result.eventId al thread che hai sospeso, poi graph.updateState + graph.invoke(null, config) riprende dal checkpoint persistito e il grafo esegue la consegna. Gli eventi spediti sono payment.received, payment.sent, wallet.deployed e webhook.test.
Il client che stai avvolgendo è aperto. Leggilo.
Non esiste un starter package LangGraph da clonare - la ricetta sopra è l'integrazione. Gli SDK blockchain0x sono open source su GitHub; questa ricetta incapsula il Python SDK (blockchain0x-python), con la superficie completa dei metodi nella documentazione. Consultala come riferimento per i body dei nodi e la verifica del webhook.
github.com/tosh-labs/blockchain0x-pythonLa superficie completa dei metodi dell'SDK e lo schema di firma dei webhook sono documentati in the docs. Inizia con una chiave sk_test_ su Base Sepolia, poi passa a sk_live_ quando il grafo riprende come previsto.
Cinque trappole specifiche di LangGraph da evitare.
Il modello di esecuzione durevole di LangGraph è potente ma ha le proprie insidie riguardo ai checkpoint, alle interruzioni e agli aggiornamenti di stato.
Non esiste un pacchetto LangGraph - un nodo semplice chiama l'SDK
Blockchain0x fornisce adattatori per LangChain e CrewAI oltre al server MCP; non esiste un pacchetto LangGraph dedicato, in npm o pip. La ricetta sopra è il percorso: un nodo grafico ordinario chiama il reale client @blockchain0x/node e riprendi con graph.updateState + graph.invoke di LangGraph. Non esiste una classe di nodo di pagamento speciale e nessun aiuto per riprendere da importare - quelli non sono mai esistiti.
Checkpointer mancante
L'interrupt() di LangGraph funziona solo se il grafo ha un checkpointer. Senza uno, lo stato evapora quando il tuo processo esce e il gestore del webhook non ha alcun thread da riprendere. Usa MemorySaver per lo sviluppo e SqliteSaver o PostgresSaver in produzione. Se il tuo grafo e il gestore del webhook girano in processi diversi, devono condividere lo stesso checkpointer (ad es. uno Postgres) affinché il gestore possa trovare il thread sospeso.
Mappare il webhook al thread giusto è compito tuo
Il webhook ti informa che un pagamento si è concluso; non conosce il tuo thread_id di LangGraph. Mantieni la tua mappatura - quando inizi un grafo, memorizza thread_id chiave dall'agente, dal destinatario o da una chiave di idempotenza che imposti, quindi cercala nel gestore. La chiamata threadFor() sopra è quella ricerca. Se sbagli questo, graph.invoke riprende il thread sbagliato o nessuno.
Gestisci il percorso senza regolamento, o sospendi per sempre
Il bordo condizionale da await_settlement instrada la consegna solo quando settled è vero. Se un pagamento non arriva mai, il thread rimane sospeso indefinitamente. Aggiungi un timeout: una pulizia programmata che riprende i thread obsoleti con settled=false in modo che il bordo instradi verso END, oppure un controllo payment.sent-versus-deadline. Un thread sospeso non costa nulla, ma non termina mai da solo.
Gli importi sono unità base USDC, come stringhe
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.