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 resolves addresses from the network config for all supported networks. See getNetworkConfig() for the full list (Base Sepolia, Base, Ethereum, Ethereum Sepolia, Arbitrum Sepolia, Polygon, Arbitrum, Optimism, Avalanche, Celo, Monad).
refundable({ network: 'eip155:84532', ... }, '0x...');  // Base Sepolia
refundable({ network: 'eip155:8453', ... }, '0x...');   // Base Mainnet
refundable({ network: 'eip155:1', ... }, '0x...');      // Ethereum

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

Deploy Operator

Deploy a PaymentOperator to use with refundable().

Examples

See merchant server examples using refundable().

Protocol Overview

Understand the escrow scheme.