Skip to main content

Payments Overview

Every order is paid the same way in outline. You confirm a quote, which finalizes an invoice, and then you settle that invoice. What differs is how the money moves: a person clicking a link on a Stripe-hosted page, an on-chain USDC transfer, or a card charge your agent authorizes in advance.

Hosted invoice

The default. A person pays a Stripe-hosted invoice page.

x402 (exact)

Your agent signs a USDC transfer; a facilitator settles it on-chain.

MPP-SPT

Your agent mints a bounded Stripe token; Stripe charges the card.

Base URLs

The sandbox is a separate environment with its own accounts, tokens, and Stripe objects. Every example in this section uses $FOUNDRY_API_URL, so either works:
Every endpoint authenticates with a bearer token, like the rest of the API. Confirming a quote and settling an invoice need a token whose role grants the Quote:Update and Invoice:Pay actions: Member, Billing, or Admin. Member is the usual role for an agent, since it also creates experiments; Billing suits someone who only handles quotes and invoices. Viewer has no access to quotes or invoices at all.

The two steps

Confirming a quote never moves money. It finalizes the invoice and hands back a payment block telling you where to pay:
kind is hosted_invoice for the default rail, carrying hosted_invoice_url instead. kind is machine when the invoice settles programmatically, and methods lists the rails this environment accepts. POST /invoices/{invoice_id}/pay is the only endpoint that settles an invoice. Call it twice: once without a credential to receive the 402 challenge, once with the credential to settle. Repeating the settling call is safe — an invoice that is already paid answers 200 with already_paid: true and charges nothing.

Choosing a rail

One header selects the rail on every call: Any other value is rejected with 400. Note the spelling: x402-exact, never x402. Both machine rails are server-side only. A browser cannot send the method or credential headers, or read the challenge headers, so drive these flows from a backend or an agent runtime. At experiment creation you can select the rail in the request body instead:
Send one or the other. If both are present they must agree, or the request is rejected with 400 (payment_method_selector_conflict).
A token issued with a machine payment policy is challenged without the header: POST /invoices/{id}/pay answers 402 offering every rail the environment serves, and whichever credential you send back decides the rail. A stock x402 client can then pay without knowing the method header exists. A stock MPP client also needs the header fallback described in MPP-SPT. Ask support@adaptyvbio.com for such a token.

What the rail pins

The rail you choose when you create the experiment binds the experiment’s quote and invoice for its whole lifetime. Two consequences:
  • Switching between machine rails later is fine. An experiment created as x402-exact can be settled with mpp-spt, and the reverse. That applies between payments, not during one: once you have taken a 402, that session owns the rail until it settles, and the header is ignored for the rest of it.
  • Crossing between the hosted-invoice rail and a machine rail is not. A quote created without a machine rail cannot be settled with one, and a machine-rail experiment cannot fall back to the hosted invoice. Both return 409. Create a fresh experiment instead.

Naming what settled

A settling 200 carries settlement_reference when the payment can be named:
Both are independently checkable — in the Stripe dashboard and on Base respectively. Treat the field as optional even on a settling response: some settlements have no reference to report.

Status codes

POST /invoices/{invoice_id}/pay answers: