Documentation
Vault402 docs
Vault402 adds HTTP 402 payments to any Express API. Agents pay on Robinhood Chain and get the response, with no accounts or API keys.
Install
Requires Node.js 18+. Developers install the SDK. An agent can install itself with one command, which also writes a new wallet key to .env.agent (mode 600, added to .gitignore).
$ npm install vault402npx vault402 init --out .env.agentNetworks
Robinhood Chain is an Ethereum Layer 2 built on Arbitrum, and gas is paid in ETH. The public RPCs are rate-limited, so pass rpcUrl with a provider endpoint in production.
| Network | network | Chain ID | Public RPC |
|---|---|---|---|
| Mainnet | "robinhood" | 4663 | rpc.mainnet.chain.robinhood.com |
| Testnet | "robinhood-testnet" | 46630 | rpc.testnet.chain.robinhood.com |
Tokens
ETH and WETH are built in. Describe USDC, Stock Tokens or any other ERC-20 by address, which you can find on the Robinhood Chain explorer. Add eip3009 to tokens that support transferWithAuthorization to enable gasless payments.
import { defineToken } from 'vault402';
export const USDC = defineToken({
symbol: 'USDC', address: '0x…', decimals: 6,
eip3009: { name: 'USD Coin', version: '2' },
});
export const TSLA = defineToken({
symbol: 'TSLA', address: '0x…', decimals: 18,
});Sell an API
Unpaid requests get a 402 that lists every accepted token. Your handler only runs after the payment is confirmed on-chain.
import { requirePayment, ETH } from 'vault402';
app.get('/premium-data',
requirePayment({
network: 'robinhood',
payTo: '0xYourWallet',
price: [
{ token: USDC, amount: '0.25' },
{ token: ETH, amount: '0.0001' },
],
settlementKey: process.env.SETTLER_KEY, // enables gasless USDC
}),
(req, res) => res.json({ data: '…', paidBy: req.vault402?.payer })
);| Option | Meaning |
|---|---|
price | One { token, amount } or a list. Human units. |
access | one-time (default), pass, or credits. |
settlementKey | Submits EIP-3009 authorizations; needs a little ETH. |
store | MemoryStore by default. Use Redis/DB for several instances. |
confirmations | Blocks to wait before accepting. Default 1. |
Pay as an agent
The budget is required. The agent only pays in tokens listed in it, and only up to the limits you set. It never pays twice for one request.
import { createAgentClient, ETH } from 'vault402';
const agent = createAgentClient({
account: process.env.AGENT_PRIVATE_KEY,
network: 'robinhood',
budget: [
{ token: USDC, maxPerPayment: '1', maxTotal: '20' },
{ token: ETH, maxPerPayment: '0.001' },
],
});
const res = await agent.fetch(url); // pays a 402 if it fits the budgetPayment schemes
transaction
The agent sends the transfer itself, with the paymentId in its calldata, then sends the tx hash. Works with ETH and any ERC-20. The agent pays gas.
authorization
The agent signs an EIP-3009 transferWithAuthorization with nonce = paymentId. The server submits it and pays the gas, so the agent needs no ETH.
Access models
| access | One payment buys |
|---|---|
{ type: 'one-time' } | This request (default) |
{ type: 'pass', durationSeconds: 3600 } | Unlimited calls for an hour |
{ type: 'credits', credits: 100 } | 100 calls, including the one that paid |
For passes and credits the server returns an access token. The agent client saves it and sends it as X-VAULT402-ACCESS on later calls.
How it works
- 01
The agent requests data. The server responds
402with a single-usepaymentIdand the accepted tokens. - 02
The agent pays on Robinhood Chain. It either sends a transfer that includes the paymentId or signs an EIP-3009 authorization with it.
- 03
The agent retries with the header
X-PAYMENT: base64(json). - 04
The server checks the receipt (or settles the authorization), marks the paymentId as used, and returns
X-PAYMENT-RESPONSE.