Integração de pagamento LangGraph.
Nenhum pacote LangGraph necessário. Um nó simples chama o cliente blockchain0x real, interrupt() suspende até que o webhook de pagamento chegue, e o gráfico retoma - durável entre execuções.
Não existe um pacote específico para LangGraph, e você não precisa de um. Um node simples no seu chama o cliente real , um suspende o grafo até o webhook de pagamento chegar, e o handler o retoma com os próprios + do LangGraph. Os pagamentos são liquidados na Base.
A execução durável torna o padrão de retomar após o pagamento natural.
A parte difícil dos pagamentos impulsionados por agentes é a lacuna assíncrona: você solicita o pagamento, o comprador paga minutos depois (ou nunca), e você precisa retomar o trabalho sem perder o estado de onde estava. A maioria dos frameworks de agentes depende de uma fila de trabalho + armazenamento de estado manual para preencher essa lacuna. O LangGraph já possui o primitivo embutido: interrupt() suspende um gráfico em um nó e um checkpointer persiste o estado no disco. Retomar é uma chamada.
A receita aproveita isso sem nenhuma maquinaria especial. Um node pay simples chama blockchain0x.payments.create. Um node await_settlement chama interrupt() para suspender, e o checkpointer persiste o estado. O handler de webhook verifica a assinatura, define settled na thread correspondente com graph.updateState e chama graph.invoke para continuar a partir do interrupt. O graph retoma exatamente de onde parou, incluindo qualquer contexto de LLM dos nodes anteriores - tudo usando as próprias APIs do LangGraph.
Instale LangGraph e o SDK principal. Nenhum pacote extra.
Node 18+ e @langchain/langgraph 0.2+ mais o cliente real @blockchain0x/node. Não há adapter de LangGraph para adicionar em nenhuma das linguagens - usuários de LangGraph em Python instalam langgraph e o cliente Python do blockchain0x e escrevem a mesma receita, com interrupt() e Command(resume=...) no lado 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 é uma chave sk_test_ de testnet ou sk_live_ de mainnet do seu painel; o cliente a lê do ambiente. BLOCKCHAIN0X_WEBHOOK_SECRET (retornado uma única vez quando você cria ou rota um webhook) é necessário no processo que trata webhooks. Se o seu grafo roda em um processo e o handler em outro, ambos precisam do mesmo checkpointer (por exemplo, um Postgres compartilhado) para que o handler possa localizar a thread suspensa.
Um gráfico de três nós: pagar, suspender, entregar.
Abaixo está um workflow completo de LangGraph com um State tipado, um nó pay que chama o blockchain0x.payments.create real, um nó await_settlement baseado em interrupt e um nó deliver que executa o trabalho dependente assim que a chain confirma que o pagamento foi movimentado.
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".
Verifique o webhook, depois retome o thread.
O manipulador verifica a assinatura com webhooks.verify do SDK Node, procura a thread LangGraph suspensa em seu próprio mapeamento, define settled com graph.updateState e chama graph.invoke(null, config) para continuar a partir da interrupção. Nenhum helper especial - essas são as próprias APIs do 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 faz HMAC-SHA256 em tempo constante sobre o corpo raw e retorna uma união discriminada - ramifique em result.ok, sem try/catch. Mapeie result.eventId para a thread que você suspendeu, então graph.updateState + graph.invoke(null, config) retoma do ponto de verificação persistido e a execução do gráfico entrega. Os eventos enviados são payment.received, payment.sent, wallet.deployed e webhook.test.
O cliente que você está envolvendo é aberto. Leia-o.
Não existe um starter package do LangGraph para clonar - a receita acima é a integração. Os SDKs da blockchain0x são open source no GitHub; esta receita encapsula o Python SDK (blockchain0x-python), com a superfície completa de métodos na documentação. Leia como referência para os corpos dos nodes e a verificação do webhook.
github.com/tosh-labs/blockchain0x-pythonA superfície completa de métodos do SDK e o esquema de assinatura do webhook estão documentados em the docs. Comece com uma chave sk_test_ na Base Sepolia e depois mude para sk_live_ quando o graph retomar da forma que você espera.
Cinco armadilhas específicas do LangGraph a evitar.
O modelo de execução durável do LangGraph é poderoso, mas tem suas próprias armadilhas em torno de pontos de verificação, interrupções e atualizações de estado.
Não há pacote LangGraph - um nó simples chama o SDK
Blockchain0x envia adaptadores para LangChain e CrewAI, além do servidor MCP; não há um pacote dedicado do LangGraph, no npm ou pip. A receita acima é o caminho: um nó gráfico comum chama o cliente real @blockchain0x/node, e você retoma com o próprio graph.updateState + graph.invoke do LangGraph. Não há uma classe especial de nó de pagamento e nenhum helper de retomar para importar - esses nunca existiram.
Checkpointer ausente
O interrupt() do LangGraph só funciona se o gráfico tiver um checkpointer. Sem um, o estado evapora quando seu processo sai e o manipulador de webhook não tem nenhuma thread para retomar. Use MemorySaver para desenvolvimento e SqliteSaver ou PostgresSaver em produção. Se seu gráfico e manipulador de webhook forem executados em processos diferentes, eles devem compartilhar o mesmo checkpointer (por exemplo, um Postgres) para que o manipulador possa encontrar a thread suspensa.
Mapear o webhook para a thread certa é seu trabalho.
O webhook informa que um pagamento foi liquidado; ele não conhece seu thread_id do LangGraph. Mantenha seu próprio mapeamento - quando você inicia um gráfico, armazene thread_id indexado pelo agente, o destinatário ou uma chave de idempotência que você definir, e então procure-a no manipulador. A chamada threadFor() acima é essa busca. Se você errar isso, graph.invoke retoma a thread errada ou nenhuma.
Gerencie o caminho sem liquidação, ou suspenda para sempre
A borda condicional de await_settlement roteia para entregar somente quando settled é verdadeiro. Se um pagamento nunca chega, a thread permanece suspensa indefinidamente. Adicione um tempo limite: uma varredura agendada que retoma threads obsoletas com settled=false para que a borda roteie para END, ou uma verificação de payment.sent-versus-deadline. Uma thread suspensa não custa nada, mas também nunca termina por conta própria.
Os valores são unidades base de USDC, como 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.