@valeo-vup/pay
v0.1.1
Published
VUP — Valeo Universal Pay. One SDK, every payment protocol. x402, MPP, and beyond.
Maintainers
Readme
@valeo/pay
VUP — Valeo Universal Pay. One SDK, every payment protocol.
AI agents shouldn't care if an API uses x402 or MPP, Base or Solana, USDC or pathUSD. @valeo/pay abstracts all of it behind a single pay() call.
Agent says "pay this endpoint"
→ VUP probes the 402 response
→ Detects x402 vs MPP
→ Selects the right chain and adapter
→ Signs the payment
→ Returns data + unified receiptInstall
pnpm add @valeo/pay
# Install only the protocols you need:
pnpm add viem # Required for EVM (Base, Tempo)
pnpm add x402-fetch # For x402 on Base/EVM
pnpm add x402-solana @solana/web3.js # For x402 on Solana
pnpm add mppx # For MPP on TempoAll protocol dependencies are optional peer deps — install only what you use.
Quick Start
import { createVup } from "@valeo/pay";
const vup = createVup({
wallet: {
evmPrivateKey: process.env.PRIVATE_KEY,
solanaPrivateKey: process.env.SOLANA_PRIVATE_KEY,
},
defaultMaxBudget: "$0.10",
});
// Agent doesn't know or care if this is x402 or MPP
const result = await vup.pay("https://api.example.com/weather?city=lisbon");
console.log(result.data); // { temperature: 22, ... }
console.log(result.receipt.protocol); // "x402" or "mpp"
console.log(result.receipt.amountUsd); // 0.01
console.log(result.receipt.receiptHash); // "a1b2c3..."How It Works
┌──────────────────────────────────────────────────┐
│ @valeo/pay │
│ │
│ pay("https://api.example.com/data") │
│ │ │
│ ┌─────┴─────┐ │
│ │ Detector │ Probes 402 response │
│ └─────┬─────┘ │
│ │ │
│ ┌──────────┼──────────┐ │
│ │ │ │ │
│ ┌────┴────┐ ┌───┴───┐ ┌───┴──────┐ │
│ │ x402 │ │ MPP │ │ Future │ │
│ │ Adapter │ │Adapter│ │ Adapter │ │
│ │ │ │ │ │ │ │
│ │Base/EVM │ │ Tempo │ │Lightning │ │
│ │ Solana │ │Stripe │ │ A2A etc. │ │
│ └────┬────┘ └───┬───┘ └───┬──────┘ │
│ │ │ │ │
│ └──────────┼──────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ Unified Receipt │ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────┘API
createVup(config)
Creates a VUP client instance.
| Option | Type | Description |
|--------|------|-------------|
| wallet.evmPrivateKey | string | EVM private key (hex) for Base and Tempo |
| wallet.solanaPrivateKey | string | Solana private key (base58) |
| wallet.evmWallet | any | Pre-configured viem wallet client |
| wallet.solanaKeypair | any | Pre-configured Solana Keypair |
| defaultMaxBudget | string | Default max budget, e.g. "$0.10" |
| defaultTimeout | number | Default timeout in ms (default: 15000) |
| stratumUrl | string | Stratum gateway URL for receipt forwarding |
| sentinelUrl | string | Sentinel URL for audit logging |
| onPayment | function | Callback after each successful payment |
| onError | function | Callback on payment error |
Returns { pay, probe, session }.
vup.pay(url, options?)
Pay for and access any paid endpoint.
| Option | Type | Description |
|--------|------|-------------|
| maxBudget | string | Max USD to pay, e.g. "$0.05" |
| method | string | HTTP method (default: "GET") |
| headers | object | Request headers |
| body | any | Request body (for POST/PUT/PATCH) |
| timeout | number | Timeout in ms |
| dryRun | boolean | Detect price only, don't pay |
| session | object | MPP session config { maxDeposit } |
| stratum | boolean | Forward receipt to Stratum |
| sentinel | boolean | Log to Sentinel |
Returns PayResult<T> with { success, data, receipt, response, detection }.
vup.probe(url, method?)
Detect the payment protocol and price without paying.
const detection = await vup.probe("https://api.example.com/premium");
console.log(detection.protocol); // "x402" or "mpp"
console.log(detection.price); // "$0.05"
console.log(detection.network); // "base", "tempo", "solana-devnet", etc.vup.session(options?)
Create an MPP session for streaming/pay-as-you-go endpoints.
const session = await vup.session({ maxDeposit: "1" });
const res1 = await session.fetch("https://api.example.com/stream/data1");
const res2 = await session.fetch("https://api.example.com/stream/data2");Supported Protocols
| Protocol | Networks | Package Required |
|----------|----------|-----------------|
| x402 | Base, Base Sepolia, EVM chains | x402-fetch + viem |
| x402 | Solana, Solana Devnet | x402-solana + @solana/web3.js |
| MPP (charge) | Tempo | mppx + viem |
| MPP (session) | Tempo | mppx + viem |
Multi-Protocol Example
const vup = createVup({
wallet: {
evmPrivateKey: process.env.PRIVATE_KEY,
solanaPrivateKey: process.env.SOLANA_KEY,
},
});
// x402 on Base
const weather = await vup.pay("https://weather.x402.dev/data");
// MPP on Tempo
const search = await vup.pay("https://parallelmpp.dev/api/search", {
method: "POST",
body: { query: "AI payments" },
});
// x402 on Solana
const nft = await vup.pay("https://solana-api.example.com/nft-data");
// All three used different protocols/chains. Agent didn't care.Unified Receipts
Every payment produces a UnifiedReceipt regardless of protocol:
{
id: "vup_a1b2c3d4e5f67890",
protocol: "x402",
network: "base",
amount: "0.01",
amountUsd: 0.01,
currency: "USDC",
payTo: "0x...",
payFrom: "0x...",
txHash: "0x...",
url: "https://api.example.com/data",
method: "GET",
timestamp: "2026-03-24T12:00:00.000Z",
receiptHash: "sha256...",
protocolReceipt: { ... }
}Receipt hashes are SHA-256 digests of canonical receipt fields, enabling Stratum integration and tamper-proof audit trails.
Error Handling
import { BudgetExceededError, DetectionError, NoWalletError } from "@valeo/pay";
try {
await vup.pay("https://expensive-api.com/data", { maxBudget: "$0.01" });
} catch (err) {
if (err instanceof BudgetExceededError) {
console.log(`Too expensive: $${err.price} > budget $${err.budget}`);
} else if (err instanceof DetectionError) {
console.log("Could not detect payment protocol");
} else if (err instanceof NoWalletError) {
console.log("Missing wallet for this chain");
}
}Design Decisions
- Protocol detection from 402 response — x402 returns payment requirements in JSON body, MPP returns
WWW-Authenticate: Paymentheader. VUP reads both. - All protocol SDKs are optional peer deps — install only what you need. Dynamic imports mean unused protocols are never loaded.
- One EVM key for Base + Tempo — Tempo is EVM-compatible, so the same private key works for both x402 on Base and MPP on Tempo.
- Budget enforcement before payment — VUP probes first, rejects if over budget, before any money moves.
- Unified receipts with SHA-256 hashes — same format regardless of protocol, enabling Stratum clearing and Sentinel audit trails.
Links
- npm: @valeo/pay
- GitHub: valeo-cash/vup
- Docs: pay.valeoprotocol.com
License
MIT
