Skip to main content
The @x402r/helpers package provides the refundable() function — a framework-agnostic helper that adds escrow configuration to x402 payment options.
This function lives in @x402r/helpers, not @x402r/merchant. Install it separately:
npm install @x402r/helpers @x402r/core

Usage

import { refundable } from '@x402r/helpers';

const option = refundable(
  {
    scheme: 'escrow',
    network: 'eip155:84532',
    payTo: '0xMerchantAddress...',
    price: '$0.01',
  },
  '0xOperatorAddress...'
);
This returns the original payment option with an extra field populated with escrow addresses and fee bounds.

Function Signature

function refundable<T extends PaymentOption>(
  option: T,
  operatorAddress: `0x${string}`,
  options?: RefundableOptions
): T & { extra: EscrowExtra }

Parameters

ParameterTypeDescription
optionPaymentOptionBase payment option (must include network)
operatorAddressAddressYour PaymentOperator contract address
optionsRefundableOptionsOptional overrides (see below)

Options & Defaults

OptionDefaultDescription
escrowAddressFrom network configAuthCaptureEscrow contract address
tokenCollectorFrom network configERC3009PaymentCollector contract address
minFeeBps0Minimum acceptable fee (0% = accept zero fees)
maxFeeBps1000Maximum acceptable fee (1000 bps = 10%)

Return Value

The function returns the original option object with an extra field added:
interface EscrowExtra {
  escrowAddress: `0x${string}`;
  operatorAddress: `0x${string}`;
  tokenCollector: `0x${string}`;
  minFeeBps: number;
  maxFeeBps: number;
}

Examples

Basic usage (defaults)

const option = refundable({
  scheme: 'escrow',
  network: 'eip155:84532',
  payTo: '0xMerchant...',
  price: '$0.01',
}, '0xOperator...');

// Result includes:
// option.extra.escrowAddress    → from network config
// option.extra.operatorAddress  → '0xOperator...'
// option.extra.tokenCollector   → from network config
// option.extra.minFeeBps        → 0
// option.extra.maxFeeBps        → 1000

Custom fee bounds

const option = refundable({
  scheme: 'escrow',
  network: 'eip155:84532',
  payTo: '0xMerchant...',
  price: '$10.00',
}, '0xOperator...', {
  maxFeeBps: 500,  // Accept up to 5% fee
});

Custom escrow address

const option = refundable({
  scheme: 'escrow',
  network: 'eip155:84532',
  payTo: '0xMerchant...',
  price: '$100.00',
}, '0xOperator...', {
  escrowAddress: '0xCustomEscrow...',
  tokenCollector: '0xCustomCollector...',
});

Supported Networks

The function automatically resolves addresses from the network config. Unsupported networks throw an error:
// Works
refundable({ network: 'eip155:84532', ... }, '0x...');  // Base Sepolia
refundable({ network: 'eip155:8453', ... }, '0x...');   // Base Mainnet

// Throws: "Unsupported network: eip155:1"
refundable({ network: 'eip155:1', ... }, '0x...');

Integration with x402

Use refundable() when constructing your 402 Payment Required response:
import { refundable } from '@x402r/helpers';

// In your server handler:
app.get('/api/resource', (req, res) => {
  res.status(402).json({
    x402Version: 2,
    accepts: [
      refundable({
        scheme: 'escrow',
        network: 'eip155:84532',
        payTo: merchantAddress,
        price: '$1.00',
      }, operatorAddress),
    ],
  });
});

Next Steps