Skip to content
LogoLogo

Accept split payments

Distribute a charge across multiple recipients

Choose a signing account

Create a server-only wallet.ts module, then import account wherever an example creates a local signing account.

wallet.ts
import { privateKeyToAccount } from 'viem/accounts'

export const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)

Split a single charge across multiple recipients in one atomic transaction. The primary recipient receives the remainder after all splits are deducted.

Split payments are useful for:

  • Marketplaces — route a platform fee to yourself and the rest to the seller
  • Referral programs — pay a bounty to the referrer on every purchase
  • Revenue sharing — distribute earnings across partners or contributors

How it works

When you add splits to a charge, the SDK constructs multiple on-chain transfers in a single transaction:

  1. Each split recipient receives their declared amount
  2. The primary recipient receives amount - sum(splits)
  3. The server verifies all transfers atomically

Server

Add a splits array to any mppx.charge call. Each entry specifies a recipient and amount.

export async function (: Request) {
  const  = await .({
    : '1.00',
    : '0x20c0000000000000000000000000000000000000', // pathUSD
    : '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // seller
    : [
      {
        : '0.10',
        : '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform fee
      },
    ],
  })()
 
  // seller receives $0.90, platform receives $0.10
  if (. === 402) return .
  return .(.({ : '...' }))
}

With per-split memos

Each split can carry its own on-chain memo for reconciliation:

const  = await .({
  : '1.00',
  : '0x20c0000000000000000000000000000000000000', // pathUSD
  : '0x6f726465722d313233', // order-123
  : '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // seller
  : [
    {
      : '0.10',
      : '0x706c6174666f726d2d666565', // platform-fee
      : '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform
    },
  ],
})()

With fee sponsorship

Split payments work with fee sponsorship. The server co-signs the multi-transfer transaction so the client doesn't need gas tokens.

const  = await .({
  : '1.00',
  : '0x20c0000000000000000000000000000000000000', // pathUSD
  : true, 
  : '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // seller
  : [
    { : '0.05', : '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC' }, // referrer
    { : '0.10', : '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' }, // platform
  ],
})()

Client

The client SDK handles split payments automatically — no client-side configuration is needed. When the server includes splits in the Challenge, the client constructs the matching multi-transfer transaction.

Validate payment recipients

Use expectedRecipients to restrict every payment recipient the client signs for. Include the primary recipient and each split recipient. This prevents a compromised server from redirecting funds to unexpected addresses.

If the server sends a Challenge with a primary or split recipient not in the allowlist, the client throws an error before signing.

Constraints

RuleLimit
Splits per charge1–10
Each split amountMust be > 0
Sum of all splitsMust be strictly less than amount
Split memoOptional, 32-byte hex hash

Next steps