Pay with a Shared Payment Token (MPP-SPT)
This rail settles from a card rather than a crypto balance. Your agent takes a402 challenge that says what the token must authorize, mints a
Stripe Shared Payment Token
bounded to those values, and hands it back; Stripe redeems it as one card
charge. The API never sees the underlying payment method, only the token.
Shared Payment Tokens are Stripe’s mechanism for
agentic commerce: a limited-scope
credential the buyer issues and the seller redeems, capped by amount, currency,
recipient, and expiry.
You need a token whose role grants Invoice:Pay — Member, Billing, or
Admin. Creating the experiment additionally needs Experiment:Create,
which Member and Admin carry but Billing does not.
Read the challenge
Create the experiment withX-Adaptyv-Payment-Method: mpp-spt to pin the rail,
confirm the quote, then call /pay with the method header and no credential.
This call commits to nothing — it opens the payment session and answers 402
with the challenge in the WWW-Authenticate response header:
id is opaque — echo it
back verbatim. It is not a Stripe object id.
The challenge is the whole handshake. request is base64url-encoded JSON
carrying everything the token must encode:
amount is in the currency’s minor unit — cents for usd, so "12500" is
$125.00.
Keep the whole challenge, not just the decoded values — your credential echoes
it back, as below. This is also why no endpoint
hands you these values without a 402: the API settles against the challenge it
stored when it opened the session, so parameters obtained any other way would
echo a challenge no session is holding. A credential sent before a challenge is
answered with 409.
501 means this environment does not serve the rail at all; 422 means the
invoice is not in a payable state.
The challenge arrives under the standard WWW-Authenticate name, so a stock
MPP client reads it without special handling.
Mint the SPT
Mint the SPT againstmethodDetails.networkId, denominated in currency,
capped at amount, and expiring no earlier than the challenge’s expires —
roughly five minutes out.
Bound the token to those four values. The API re-checks them against the
challenge before handing the token to Stripe, and Stripe refuses a token that
authorizes less than the amount due, targets another recipient, uses another
currency, or has expired. Bound looser and you are carrying risk for nothing.
The challenge is valid for five minutes. Mint and settle inside that window. A
credential echoing an expired challenge is refused with 409; call /pay again
without a credential to take a fresh challenge on the same invoice.
Retry with the credential
The credential is base64url without padding, wrapping the token and an echo of the challenge:challenge value verbatim from the WWW-Authenticate parameters,
request included as the raw string you received. The API compares your echo
against the challenge it issued, so a re-encoded request is refused even
though it decodes to the same JSON.
Send the credential in the Authorization header under the Payment scheme,
and move your API token to X-Adaptyv-Api-Key:
If the charge succeeds but the response never reaches you, repeat the call. The
API returns the charge it already made rather than making a second one.