LangGraph betalingsintegratie.
Geen LangGraph-pakket nodig. Een gewone node roept de echte blockchain0x-client aan, interrupt() pauzeert totdat de betalingswebhook aankomt, en de grafiek hervat - duurzaam over runs.
Er is geen LangGraph-pakket, en je hebt er ook geen nodig. Een gewone node in je roept de echte -client aan, een pauzeert de graph totdat de payment webhook binnenkomt, en de handler hervat hem met LangGraph's eigen + . Betalingen worden afgerekend op Base.
Duurzame uitvoering maakt het hervatten-na-betaling patroon natuurlijk.
Het moeilijke deel van agent-gedreven betalingen is de async kloof: je vraagt om betaling, de koper betaalt minuten later (of nooit), en je moet je werk hervatten zonder de staat te verliezen waar je was. De meeste agentframeworks vertrouwen op een taakwachtrij + handmatige statusopslag om deze kloof te overbruggen. LangGraph heeft de primitieve al ingebouwd: interrupt() pauzeert een grafiek op een knooppunt en een checkpointer bewaart de status op schijf. Hervatten is één oproep.
De aanpak leunt hierop zonder speciale mechanismen. Een gewone pay node roept blockchain0x.payments.create aan. Een await_settlement node roept interrupt() aan om te pauzeren, en de checkpointer slaat de state op. De webhook handler verifieert de signature, zet settled op de overeenkomende thread met graph.updateState, en roept graph.invoke aan om door te gaan vanaf de interrupt. De graph gaat precies verder waar hij was gebleven, inclusief alle LLM context uit eerdere nodes - allemaal met de eigen APIs van LangGraph.
Installeer LangGraph en de kern SDK. Geen extra pakket.
Node 18+ en @langchain/langgraph 0.2+ plus de echte @blockchain0x/node-client. Er is geen LangGraph-adapter om in beide talen toe te voegen - Python LangGraph-gebruikers installeren langgraph en de blockchain0x Python-client en schrijven hetzelfde recept, met interrupt() en Command(resume=...) aan de Python-kant.
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 is een sk_test_ testnet- of sk_live_ mainnet-sleutel uit je dashboard; de client leest deze uit de omgeving. BLOCKCHAIN0X_WEBHOOK_SECRET (eenmalig teruggegeven wanneer je een webhook aanmaakt of roteert) is nodig in het proces dat webhooks verwerkt. Als je graph in één proces draait en de handler in een ander, hebben beide dezelfde checkpointer nodig (bijv. gedeelde Postgres) zodat de handler de onderbroken thread kan vinden.
Een drie-knooppunt grafiek: betalen, opschorten, leveren.
Hieronder staat een complete LangGraph-workflow met een getypeerde State, een pay-node die de echte blockchain0x.payments.create aanroept, een op interrupts gebaseerde await_settlement-node en een deliver-node die het afhankelijke werk uitvoert zodra de chain bevestigt dat de betaling is verplaatst.
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".
Verifieer de webhook, en hervat dan de thread.
De handler verifieert de handtekening met webhooks.verify van de Node SDK, kijkt de geschorste LangGraph-thread op vanuit jouw eigen mapping, stelt settled in met graph.updateState, en roept graph.invoke(null, config) aan om door te gaan vanaf de onderbreking. Geen speciale helper - dat zijn de eigen API's van 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 doet HMAC-SHA256 in constante tijd over de raw body en retourneert een gediscrimineerde unie - tak op result.ok, geen try/catch. Koppel result.eventId aan de thread die je hebt gepauzeerd, dan graph.updateState + graph.invoke(null, config) hervat vanaf het opgeslagen checkpoint en de grafiek draait leveringen. De verzonden evenementen zijn payment.received, payment.sent, wallet.deployed, en webhook.test.
De client die je aan het wikkelen bent is open. Lees het.
Er is geen LangGraph starter package om te klonen - de bovenstaande recipe is de integratie. De blockchain0x SDKs zijn open source op GitHub; deze recipe omhult de Python SDK (blockchain0x-python), met de volledige method surface in de docs. Lees die als referentie voor de node bodies en de webhook verify.
github.com/tosh-labs/blockchain0x-pythonDe volledige SDK method surface en het webhook signature scheme zijn gedocumenteerd in de docs. Begin met een sk_test_ key op Base Sepolia en schakel daarna over naar sk_live_ zodra de graph hervat zoals je verwacht.
Vijf LangGraph-specifieke valkuilen om te vermijden.
LangGraph's duurzame uitvoeringsmodel is krachtig maar heeft zijn eigen valkuilen rond checkpoints, onderbrekingen en statusupdates.
Er is geen LangGraph-pakket - een gewone node roept de SDK aan
Blockchain0x levert adapters voor LangChain en CrewAI plus de MCP-server; er is geen speciaal LangGraph-pakket, in npm of pip. Het bovenstaande recept is het pad: een gewone grafknoop roept de echte @blockchain0x/node-client aan, en u hervat met LangGraph's eigen graph.updateState + graph.invoke. Er is geen speciale betalingsnodeklasse en geen hervathelper om te importeren - die hebben nooit bestaan.
Ontbrekende checkpointer
LangGraph's interrupt() werkt alleen als de graph een checkpointer heeft. Zonder die verdwijnt de state zodra je proces eindigt en heeft de webhook handler geen thread om te hervatten. Gebruik MemorySaver voor ontwikkeling en SqliteSaver of PostgresSaver in productie. Als je graph en webhook handler in verschillende processen draaien, moeten ze dezelfde checkpointer delen (bijv. één Postgres) zodat de handler de gesuspendeerde thread kan vinden.
Het toewijzen van de webhook aan de juiste thread is uw taak
De webhook vertelt je dat een betaling is vereffend; het kent jouw LangGraph thread_id niet. Houd jouw eigen mapping bij - wanneer je een grafiek start, sla je thread_id op, gekoppeld aan de agent, de ontvanger, of een idempotentie-sleutel die je hebt ingesteld, en kijk het dan op in de handler. De threadFor() aanroep hierboven is die lookup. Krijg dit verkeerd en graph.invoke hervat de verkeerde thread of helemaal geen.
Verwerk het pad zonder afwikkeling, of schort het voor altijd op
De voorwaardelijke rand van await_settlement routeert alleen naar levering wanneer settled waar is. Als een betaling nooit aankomt, blijft de thread onbeperkt geschorst. Voeg een time-out toe: een geplande sweep die verouderde threads hervat met settled=false zodat de rand naar END routeert, of een payment.sent-versus-deadline controle. Een geschorste thread kost niets, maar het voltooit ook nooit op zichzelf.
Bedragen zijn USDC basis eenheden, als strings
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.