Open-source spend governance for AI agents. Issue single-use virtual cards or pay x402-enabled APIs with USDC — with policy enforcement, audit logging, and human-in-the-loop approval.
Agent (LangGraph / CrewAI / any framework)
│
▼
┌────────────────────────────────────────┐
│ AgentWallet │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Policy Engine│ │ Audit Logger │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ ┌──────▼─────────────────▼─────────┐ │
│ │ Payment Rails │ │
│ │ Card: Mock │ Stripe │ StripeMPP │ │
│ │ │ │
│ │ x402: X402Gateway │ MockX402 │ │
│ └──────────────────────────────────┘ │
└────────────────────────────────────────┘
pip install paygraphWith LangGraph support:
pip install paygraph[langgraph]With CrewAI support:
pip install paygraph[crewai]With x402 support (EVM + Solana USDC payments):
pip install paygraph[x402]With live demo (includes LLM providers):
pip install paygraph[live]from paygraph import AgentWallet, SpendPolicy, MockGateway
wallet = AgentWallet(
gateway=MockGateway(auto_approve=True),
policy=SpendPolicy(
max_transaction=25.0,
daily_budget=100.0,
blocked_vendors=["doordash"],
),
)
result = wallet.request_spend(
amount=4.20,
vendor="Anthropic API",
justification="Need Claude credits for document summarization.",
)
print(result) # Card approved. PAN: 4111..., CVV: 123, Expiry: 12/28from paygraph import AgentWallet, SpendPolicy, StripeCardGateway
wallet = AgentWallet(
gateway=StripeCardGateway(api_key="sk_test_..."),
policy=SpendPolicy(max_transaction=50.0),
)
result = wallet.request_spend(
amount=4.20,
vendor="Anthropic API",
justification="API credits for task completion.",
)StripeCardGateway accepts the following parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
required | Stripe secret key (sk_test_... or sk_live_...) |
cardholder_id |
str | None |
None |
Existing cardholder ID to use (skips auto-creation) |
currency |
str |
"usd" |
Card currency (e.g. "eur", "gbp") |
billing_address |
dict | None |
US address | Cardholder billing address (line1, city, postal_code, country) |
single_use |
bool |
True |
Mint a new card per transaction; set False to reuse one card |
When single_use=False, a single card is created on the first spend and reused for subsequent calls (spending limit is updated each time).
For sellers that accept Stripe machine payments (MPP / agentic commerce), use StripeMPPGateway to issue scoped Shared Payment Tokens instead of virtual cards.
Requires Stripe machine payments access (preview API). See Stripe docs.
from paygraph import AgentWallet, SpendPolicy, StripeMPPGateway
wallet = AgentWallet(
gateway=StripeMPPGateway(
api_key="sk_test_...",
payment_method="pm_...",
grantee="profile_...",
),
policy=SpendPolicy(max_transaction=50.0),
)
result = wallet.request_spend(
amount=4.20,
vendor="Anthropic API",
justification="API credits for task completion.",
)
print(result) # SPT approved. Token: spt_... (spend limit: $4.20)| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
required | Stripe secret key (sk_test_... or sk_live_...) |
payment_method |
str |
required | Saved PaymentMethod id (pm_...) |
grantee |
str |
required | Seller identifier (typically profile_...) |
currency |
str |
"usd" |
ISO currency code |
expires_in_seconds |
int |
3600 |
Token lifetime from issuance in seconds |
x402 is an HTTP 402-based protocol for machine-to-machine payments. Instead of minting a card, the gateway makes an HTTP request, handles the 402→sign→retry cycle on-chain, and returns the API response.
from paygraph import AgentWallet, X402Gateway, SpendPolicy
wallet = AgentWallet(
x402_gateway=X402Gateway(evm_private_key="0x..."), # Base/Polygon USDC
policy=SpendPolicy(max_transaction=5.0),
)
response = wallet.request_x402(
url="https://api.example.com/paid-endpoint",
amount=0.01,
vendor="ExampleAPI",
justification="Need data for analysis.",
)
print(response) # The API response bodySupports both EVM (Base, Polygon, etc.) and Solana:
# Solana only
gateway = X402Gateway(svm_private_key="BASE58_KEY")
# Both networks
gateway = X402Gateway(evm_private_key="0x...", svm_private_key="BASE58_KEY")For testing without blockchain:
from paygraph import AgentWallet, MockX402Gateway
wallet = AgentWallet(
x402_gateway=MockX402Gateway(auto_approve=True, response_body='{"data": 42}'),
)from paygraph import AgentWallet, SpendPolicy, MockX402Gateway
wallet = AgentWallet(
x402_gateway=MockX402Gateway(auto_approve=True),
policy=SpendPolicy(max_transaction=25.0, blocked_vendors=["doordash"]),
)
# wallet.spend_tool → card payments, wallet.x402_tool → x402 API payments
tools = [wallet.spend_tool, wallet.x402_tool]
# Use with LangGraph
from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-6")
agent = create_react_agent(llm, tools=tools)
result = agent.invoke({"messages": [("user", "Buy $4.20 in API credits from Anthropic")]})pip install paygraph[crewai]from crewai import Agent, Task, Crew
from paygraph import AgentWallet, SpendPolicy, MockGateway
wallet = AgentWallet(
gateway=MockGateway(auto_approve=True),
policy=SpendPolicy(max_transaction=25.0),
)
agent = Agent(
role="Purchasing Agent",
goal="Buy API credits when needed",
tools=[wallet.crewai_tool],
)pip install paygraph[mcp]Run the MCP server over stdio:
PAYGRAPH_GATEWAY=mock \
PAYGRAPH_DAILY_BUDGET=100 \
PAYGRAPH_MAX_TRANSACTION=25 \
paygraph-mcpClaude Desktop config:
{
"mcpServers": {
"paygraph": {
"command": "paygraph-mcp",
"env": {
"PAYGRAPH_GATEWAY": "mock",
"PAYGRAPH_DAILY_BUDGET": "100",
"PAYGRAPH_MAX_TRANSACTION": "25"
}
}
}
}SpendPolicy accepts the following parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
max_transaction |
float |
50.0 |
Maximum amount per transaction (dollars) |
daily_budget |
float |
200.0 |
Maximum total spend per day |
allowed_vendors |
list[str] | None |
None |
If set, only these vendors are allowed (case-insensitive substring match) |
blocked_vendors |
list[str] | None |
None |
Vendors that are always denied (case-insensitive substring match) |
allowed_mccs |
list[int] | None |
None |
Merchant category code allowlist |
require_justification |
bool |
True |
Require non-empty justification string |
| Variable | Required for | Description |
|---|---|---|
ANTHROPIC_API_KEY |
--live (default) |
Anthropic API key for Claude LLM |
OPENAI_API_KEY |
--live --model openai |
OpenAI API key for GPT LLM |
STRIPE_API_KEY |
--stripe or --stripe-mpp |
Stripe secret key (sk_test_ or sk_live_) |
STRIPE_CURRENCY |
Stripe gateways (optional) | Currency for card/SPT limits (default: usd) |
STRIPE_BILLING_COUNTRY |
--stripe (optional) |
Billing address country code (e.g. FR) |
STRIPE_CARDHOLDER_ID |
--stripe (optional) |
Reuse an existing cardholder ID |
STRIPE_MPP_PAYMENT_METHOD |
--stripe-mpp |
PaymentMethod id (pm_...) for SPT issuance |
STRIPE_MPP_GRANTEE |
--stripe-mpp |
Seller grantee id (typically profile_...) |
STRIPE_MPP_EXPIRES_IN_SECONDS |
--stripe-mpp (optional) |
SPT lifetime in seconds (default: 3600) |
EVM_PRIVATE_KEY |
x402 (EVM) | EVM private key for Base/Polygon USDC payments |
SVM_PRIVATE_KEY |
x402 (Solana) | Solana private key (base58) for USDC payments |
Copy .env.example to .env and fill in your keys:
cp .env.example .env# Run simulated demo (no API keys needed)
paygraph demo
# Run live demo with a real LLM
export ANTHROPIC_API_KEY=sk-ant-...
paygraph demo --live
# Use OpenAI instead
export OPENAI_API_KEY=sk-...
paygraph demo --live --model openai
# Use Stripe Issuing for real card issuance
export STRIPE_API_KEY=sk_test_...
paygraph demo --live --stripe
# Use Stripe MPP (Shared Payment Tokens)
export STRIPE_API_KEY=sk_test_...
export STRIPE_MPP_PAYMENT_METHOD=pm_...
export STRIPE_MPP_GRANTEE=profile_...
paygraph demo --live --stripe-mppMIT