Skip to content
LogoLogo

Mppx.compose

Present multiple payment options

Combines multiple method handlers into a single route handler that presents all methods to the client via multiple WWW-Authenticate headers.

Usage

Present both stablecoin and Stripe card payment options for a single endpoint. The client picks whichever method it supports.

import { , ,  } from 'mppx/server'
 
const  = '0x20c0000000000000000000000000000000000000'
const  = '0x20C000000000000000000000b9537d11c60E8b50'
const  = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
 
const  = .({  })
const  = .({
  : 2,
  : 'acct_1234',
  : ['card'],
  : 'sk_live_...',
})
 
const  = .({ : [, ] })
 
export async function (: Request) {
  const  = await .(
    [, { : '1', :  }],
    [, { : '1', :  }],
    [, { : '1', : 'usd' }],
  )()
 
  if (. === 402) return .
  return .(.({ : '...' }))
}

Nested compositions

Use the static Mppx.compose() function to combine configured handlers or another composed handler. Credential dispatch and discovery metadata include every nested offer.

const stablecoins = Mppx.compose(
  mppx.tempo.charge({ amount: '1', currency: pathUSD }),
  mppx.tempo.charge({ amount: '1', currency: USDCe }),
)
 
const paid = Mppx.compose(
  stablecoins,
  mppx.stripe.charge({ amount: '1', currency: 'usd' }),
)

Behavior

  • No Credential present: Calls all handlers and merges their 402 Challenges into a single response with multiple WWW-Authenticate headers.
  • Intent shorthand: When multiple registered methods share an intent, mppx.charge(options) and other intent functions implicitly compose every matching method. Use explicit composition when offers need different options.
  • Offer policies: Calls each method's canOffer hook, then the instance-level selectOffers hook, before generating Payment auth, x402, or HTML offers. Static compositions apply canOffer; direct method handlers don't.
  • Accept-Payment present: Ranks and filters the merged Challenges by the client's supported method/intent entries. Entries with q=0 are excluded. If the header is invalid or filters out every Challenge, all Challenges are returned.
  • Credential present: Dispatches to the handler matching the Credential's method and intent without re-running offer policies.
  • Discovery enabled: Exposes every configured offer to discovery() and proxy metadata, including offers from nested compositions.

Signatures

Instance

type InstanceCompose = (
  ...entries: readonly [Method.Server | MethodHandler | string, Options][]
) => ComposedHandler

Static

type StaticCompose = (
  ...handlers: readonly (ComposedHandler | ConfiguredHandler)[]
) => ComposedHandler

Return type

type ReturnType = (input: Request) => Promise<
  | { status: 402; challenge: Response }
  | { status: 200; withReceipt: <T>(response: T) => T }
>

Parameters

...entries

  • Type: readonly [Method.Server | MethodHandler | string, Options][]

Each entry is a tuple of a method reference (or string key like "tempo/charge") and the request options for that method. Requires at least one entry.

...handlers

  • Type: readonly (ComposedHandler | ConfiguredHandler)[]

Configured route handlers returned by an mppx method or another static composition. Requires at least one handler.