@shade402/langgraph
v0.0.1
Published
LangGraph.js integration for X402 payment protocol
Maintainers
Readme
@shade402/langgraph
LangGraph.js integration for X402 payment protocol. Provides reusable nodes and utilities for handling X402 payments in LangGraph workflows.
Overview
The LangGraph package provides payment nodes and helper functions that can be integrated into LangGraph state machine workflows. This enables complex AI agent workflows to automatically handle payments for API access as part of their execution graph.
Features
- Reusable payment nodes for LangGraph workflows
- Payment state management
- Conditional edges for payment flow control
- Automatic payment handling in workflow steps
- Support for all HTTP methods
- Full TypeScript support
- Seamless integration with LangGraph state machines
Installation
npm install @shade402/langgraph
# or
pnpm add @shade402/langgraph
# or
yarn add @shade402/langgraphDependencies
@shade402/core: Core X402 protocol implementation@shade402/client: X402 HTTP client@solana/web3.js: Solana wallet operations@langchain/langgraph: LangGraph.js framework
Usage
Basic Workflow Setup
import { StateGraph } from '@langchain/langgraph';
import {
paymentNode,
fetchWithPaymentNode,
checkPaymentRequired,
checkPaymentCompleted,
PaymentState
} from '@shade402/langgraph';
import { Keypair } from '@solana/web3.js';
// Create wallet for payments
const wallet = Keypair.generate();
// Define workflow
const workflow = new StateGraph<PaymentState>({
channels: {
wallet_keypair: null,
api_url: null,
api_response: null,
payment_completed: null,
payment_error: null,
payment_required: null,
max_payment_amount: null,
http_method: null,
allow_local: null,
rpc_url: null
}
});
// Add nodes
workflow.addNode('fetch_api', fetchWithPaymentNode);
workflow.addNode('make_payment', paymentNode);
workflow.addNode('process_response', async (state: PaymentState) => {
return {
...state,
processed: true,
result: state.api_response
};
});
// Add edges
workflow.setEntryPoint('fetch_api');
workflow.addConditionalEdges(
'fetch_api',
checkPaymentRequired,
{
payment_required: 'make_payment',
success: 'process_response'
}
);
workflow.addEdge('make_payment', 'fetch_api'); // Retry after payment
// Compile and run
const app = workflow.compile();
const result = await app.invoke({
wallet_keypair: wallet,
api_url: 'https://api.example.com/premium-data',
max_payment_amount: '1.0',
rpc_url: 'https://api.devnet.solana.com'
});Advanced Workflow with Error Handling
import { StateGraph } from '@langchain/langgraph';
import {
paymentNode,
fetchWithPaymentNode,
checkPaymentRequired,
checkPaymentCompleted,
PaymentState
} from '@shade402/langgraph';
import { Keypair } from '@solana/web3.js';
const wallet = Keypair.generate();
const workflow = new StateGraph<PaymentState>({
channels: {
wallet_keypair: null,
api_url: null,
api_response: null,
payment_completed: null,
payment_error: null,
payment_required: null,
max_payment_amount: null,
http_method: null,
allow_local: null,
rpc_url: null,
retry_count: null
}
});
// Add nodes
workflow.addNode('fetch_api', fetchWithPaymentNode);
workflow.addNode('make_payment', paymentNode);
workflow.addNode('handle_error', async (state: PaymentState) => {
return {
...state,
error_handled: true
};
});
workflow.addNode('process_response', async (state: PaymentState) => {
return {
...state,
processed: true
};
});
// Entry point
workflow.setEntryPoint('fetch_api');
// Conditional routing
workflow.addConditionalEdges(
'fetch_api',
checkPaymentRequired,
{
payment_required: 'make_payment',
success: 'process_response',
error: 'handle_error'
}
);
workflow.addConditionalEdges(
'make_payment',
checkPaymentCompleted,
{
success: 'fetch_api', // Retry after payment
error: 'handle_error'
}
);
const app = workflow.compile();API Reference
PaymentState
Interface for payment-related state in LangGraph workflows.
interface PaymentState {
wallet_keypair?: Keypair;
api_url?: string;
api_response?: string;
payment_completed?: boolean;
payment_error?: string | null;
payment_required?: boolean;
max_payment_amount?: string;
http_method?: string;
allow_local?: boolean;
rpc_url?: string;
[key: string]: any;
}paymentNode
Node that handles X402 payment and retries the API request.
async function paymentNode(state: PaymentState): Promise<PaymentState>Required State:
wallet_keypair: Keypair for making paymentsapi_url: URL to fetch after payment
Optional State:
rpc_url: Solana RPC URLallow_local: Allow localhost URLsmax_payment_amount: Maximum payment amount
Returns State:
api_response: API response textpayment_completed: boolean indicating successpayment_error: Error message if payment failed
fetchWithPaymentNode
Node that fetches an API endpoint and handles payment if required.
async function fetchWithPaymentNode(state: PaymentState): Promise<PaymentState>Required State:
wallet_keypair: Keypair for making paymentsapi_url: URL to fetch
Optional State:
rpc_url: Solana RPC URLallow_local: Allow localhost URLshttp_method: HTTP method (default: 'GET')max_payment_amount: Maximum payment amount
Returns State:
api_response: API response text if successfulpayment_required: boolean indicating if payment is neededpayment_error: Error message if fetch failed
checkPaymentRequired
Conditional edge function to check if payment is required.
function checkPaymentRequired(state: PaymentState): stringReturns:
'payment_required': If payment is needed'success': If request succeeded'error': If request failed
checkPaymentCompleted
Conditional edge function to check if payment was completed successfully.
function checkPaymentCompleted(state: PaymentState): stringReturns:
'success': If payment completed successfully'error': If payment failed
Examples
Simple Payment Flow
import { StateGraph } from '@langchain/langgraph';
import {
paymentNode,
fetchWithPaymentNode,
checkPaymentRequired,
PaymentState
} from '@shade402/langgraph';
import { Keypair } from '@solana/web3.js';
const wallet = Keypair.generate();
const workflow = new StateGraph<PaymentState>({
channels: {
wallet_keypair: null,
api_url: null,
api_response: null,
payment_completed: null,
payment_error: null,
payment_required: null
}
});
workflow.addNode('fetch', fetchWithPaymentNode);
workflow.addNode('pay', paymentNode);
workflow.addNode('done', (state) => ({ ...state, done: true }));
workflow.setEntryPoint('fetch');
workflow.addConditionalEdges('fetch', checkPaymentRequired, {
payment_required: 'pay',
success: 'done'
});
workflow.addEdge('pay', 'fetch'); // Retry after payment
const app = workflow.compile();
const result = await app.invoke({
wallet_keypair: wallet,
api_url: 'https://api.example.com/data'
});Multi-Step Workflow
import { StateGraph } from '@langchain/langgraph';
import {
paymentNode,
fetchWithPaymentNode,
checkPaymentRequired,
checkPaymentCompleted,
PaymentState
} from '@shade402/langgraph';
import { Keypair } from '@solana/web3.js';
const wallet = Keypair.generate();
const workflow = new StateGraph<PaymentState>({
channels: {
wallet_keypair: null,
api_url: null,
api_response: null,
payment_completed: null,
payment_error: null,
payment_required: null,
step: null
}
});
// Step 1: Fetch initial data
workflow.addNode('step1', async (state: PaymentState) => {
return {
...state,
api_url: 'https://api.example.com/data',
step: 1
};
});
// Step 2: Fetch with payment
workflow.addNode('fetch', fetchWithPaymentNode);
// Step 3: Make payment if needed
workflow.addNode('pay', paymentNode);
// Step 4: Process response
workflow.addNode('process', async (state: PaymentState) => {
return {
...state,
processed: true,
result: JSON.parse(state.api_response || '{}')
};
});
workflow.setEntryPoint('step1');
workflow.addEdge('step1', 'fetch');
workflow.addConditionalEdges('fetch', checkPaymentRequired, {
payment_required: 'pay',
success: 'process'
});
workflow.addConditionalEdges('pay', checkPaymentCompleted, {
success: 'fetch',
error: 'process'
});
const app = workflow.compile();Error Handling Workflow
import { StateGraph } from '@langchain/langgraph';
import {
paymentNode,
fetchWithPaymentNode,
checkPaymentRequired,
PaymentState
} from '@shade402/langgraph';
import { Keypair } from '@solana/web3.js';
const wallet = Keypair.generate();
const workflow = new StateGraph<PaymentState>({
channels: {
wallet_keypair: null,
api_url: null,
api_response: null,
payment_completed: null,
payment_error: null,
payment_required: null,
retry_count: null
}
});
workflow.addNode('fetch', fetchWithPaymentNode);
workflow.addNode('pay', paymentNode);
workflow.addNode('handle_error', async (state: PaymentState) => {
const retryCount = (state.retry_count || 0) + 1;
if (retryCount > 3) {
return {
...state,
retry_count: retryCount,
failed: true
};
}
return {
...state,
retry_count: retryCount
};
});
workflow.setEntryPoint('fetch');
workflow.addConditionalEdges('fetch', (state: PaymentState) => {
if (state.payment_error) return 'error';
if (state.payment_required) return 'payment_required';
return 'success';
}, {
payment_required: 'pay',
success: 'done',
error: 'handle_error'
});
workflow.addConditionalEdges('pay', (state: PaymentState) => {
return state.payment_completed ? 'success' : 'error';
}, {
success: 'fetch',
error: 'handle_error'
});State Management
The payment nodes work with LangGraph state channels. You can extend the state with additional fields:
interface ExtendedPaymentState extends PaymentState {
user_id?: string;
session_id?: string;
metadata?: Record<string, any>;
}Security Considerations
- Store wallet keys securely (environment variables, key management service)
- Use
max_payment_amountto prevent excessive payments - Set
allow_local: falsein production - Monitor workflow execution and payment patterns
- Use mainnet RPC endpoints for production
- Implement proper error handling and retry limits
- Validate API URLs to prevent SSRF attacks
TypeScript Support
The package is written in TypeScript and provides full type definitions:
import type {
PaymentState
} from '@shade402/langgraph';Integration with LangGraph
This package is designed to work seamlessly with LangGraph.js state machines. The nodes are regular async functions that take and return state, making them compatible with LangGraph's execution model.
License
MIT
