SDK Reference
Escrow API
Low-level and high-level APIs for x402 escrow management, settlement, and balance tracking.
Escrow API
The SDK provides two layers for managing x402 escrow payments: the high-level X402Registry and the low-level EscrowModule.
X402Registry (High-Level)
Access via client.x402. Handles cost estimation, payment preparation, header generation, settlement, and balance tracking.
Estimate Cost
// estimateCost reads the agent's on-chain pricing tiers and volume curve
// to calculate the total cost for a given number of calls.
// Returns: { totalCost, effectivePricePerCall, hasVolumeCurve, tiers }
const estimate = await client.x402.estimateCost(
agentWallet, // PublicKey: the agent you want to pay
100, // number of calls you plan to make
);
console.log(estimate.totalCost.toString()); // BN → string
console.log(estimate.effectivePricePerCall.toString()); // weighted average
console.log(estimate.hasVolumeCurve); // has tiered pricing?Prepare Payment
Creates escrow and deposits funds in a single transaction:
// preparePayment sends one Solana TX: creates escrow PDA + deposits lamports.
// Returns a PaymentContext with all the derived PDAs needed for headers.
const ctx = await client.x402.preparePayment(agentWallet, {
pricePerCall: 1_000, // lamports per call (number, string, or BN)
maxCalls: 500, // max calls allowed (0 = unlimited)
deposit: 500_000, // initial deposit in lamports
expiresAt: 0, // Unix timestamp (0 = never expires)
volumeCurve: [ // optional: tiered pricing breakpoints
{ afterCalls: 100, pricePerCall: 800 }, // 20% discount after 100 calls
],
});| Option | Type | Default | Description |
|---|---|---|---|
pricePerCall | number or string or BN | Required | Base price per call |
maxCalls | number or string or BN | 0 | Max calls (0 = unlimited) |
deposit | number or string or BN | Required | Initial deposit amount |
expiresAt | number or string or BN | 0 | Unix timestamp (0 = never) |
volumeCurve | Array | Empty | Volume discount breakpoints |
tokenMint | PublicKey or null | null | SPL token mint |
tokenDecimals | number | 9 | Token decimal places |
Build Headers
// From a PaymentContext (returned by preparePayment)
const headers = client.x402.buildPaymentHeaders(ctx);
// Returns: { "X-Payment-Protocol", "X-Payment-Escrow", "X-Payment-Depositor", ... }
// From an existing escrow (looks up the PDA on-chain)
const headers = await client.x402.buildPaymentHeadersFromEscrow(agentWallet);Settle
// Agent calls settle() to claim payment for calls served.
// depositorWallet: the client who funded the escrow (identifies which escrow)
// 5: number of calls to settle
// "service-data-v1": service data string (auto-hashed to SHA-256)
const receipt = await client.x402.settle(depositorWallet, 5, "service-data-v1");Batch Settle
// settleBatch combines multiple settlements in one TX. Max 10 entries.
const batch = await client.x402.settleBatch(depositorWallet, [
{ calls: 3, serviceData: "batch-1" }, // settle 3 calls
{ calls: 7, serviceData: "batch-2" }, // settle 7 calls
]);Balance
const balance = await client.x402.getBalance(agentWallet);| Field | Type | Description |
|---|---|---|
balance | BN | Current remaining balance |
totalDeposited | BN | Cumulative deposits |
totalSettled | BN | Cumulative settlements |
callsRemaining | number | Remaining calls |
isExpired | boolean | Expiry check |
affordableCalls | number | Calls the budget allows |
Additional Methods
// Add more funds to an existing escrow (in lamports).
await client.x402.addFunds(agentWallet, 50_000);
// Withdraw funds from an escrow you own (must be the depositor).
await client.x402.withdrawFunds(agentWallet, 25_000);
// Close the escrow PDA. Balance must be 0. Reclaims ~0.004 SOL rent.
await client.x402.closeEscrow(agentWallet);
// Check if an escrow exists for this agent (returns boolean).
const exists = await client.x402.hasEscrow(agentWallet);
// Fetch the raw escrow account data (or null if not found).
const escrow = await client.x402.fetchEscrow(agentWallet);
// Verify a settlement TX by parsing its events.
const events = await client.x402.verifySettlement(txSignature);EscrowModule (Low-Level)
Access via client.escrow. Direct Anchor instruction wrappers.
Create
import { BN } from "@coral-xyz/anchor";
// Low-level: all values must be BN. No automatic type conversion.
// Use the X402Registry (client.x402) for automatic conversions.
await client.escrow.create(agentWallet, {
pricePerCall: new BN(1_000_000), // 1,000,000 lamports per call
maxCalls: new BN(100), // max 100 calls (BN(0) = unlimited)
initialDeposit: new BN(100_000_000), // deposit 0.1 SOL
expiresAt: null, // null = never expires
volumeCurve: null, // null = flat pricing
tokenMint: null, // null = native SOL
tokenDecimals: null, // null = defaults to 9 (SOL)
});Deposit
await client.escrow.deposit(agentWallet, new BN(50_000_000));Settle
import { sha256, hashToArray } from "@oobe-protocol-labs/synapse-sap-sdk/utils";
// Low-level settle: requires BN for calls and pre-hashed service data.
const serviceHash = hashToArray(sha256("service-record-001")); // number[32]
await client.escrow.settle(
depositorWallet, // PublicKey: the client's wallet
new BN(5), // number of calls to settle
serviceHash, // 32-byte SHA-256 hash
);Batch Settle
// Low-level batch settle: each entry must use BN and pre-hashed service data.
// Max 10 entries per batch (LIMITS.MAX_BATCH_SETTLEMENTS).
await client.escrow.settleBatch(depositorWallet, [
{ callsToSettle: new BN(3), serviceHash: hashToArray(sha256("batch-1")) },
{ callsToSettle: new BN(7), serviceHash: hashToArray(sha256("batch-2")) },
]);Withdraw and Close
// Withdraw partial funds (must be the depositor).
await client.escrow.withdraw(agentWallet, new BN(25_000_000));
// Close escrow PDA. Balance must be 0. Reclaims rent to payer.
await client.escrow.close(agentWallet);