Pay invoice
Settles the given invoice. How it settles is chosen by the
X-Adaptyv-Payment-Method request header:
| Header value | Behaviour |
|---|---|
| (absent) | Returns the current invoice state; pay via the hosted invoice URL |
mpp-spt | Settles from a Stripe shared payment token |
x402-exact | Settles on-chain with an x402 exact USDC transfer |
This is the only endpoint that settles an invoice. The flow is two steps:
POST /quotes/{quote_id}/confirm issues the invoice and returns a payment
pointer to this route, then POST /invoices/{invoice_id}/pay settles it.
Send the first call with the method header and no credential. It answers
402, and the challenge is carried in the response headers, not the
body — PAYMENT-REQUIRED for x402-exact, WWW-Authenticate for
mpp-spt.
mpp-spt is only supported via the MCP server for now.
Repeat the call with the signed credential to settle — PAYMENT-SIGNATURE
for x402-exact, Authorization for mpp-spt — and the response is 200
with the paid invoice. Repeating it again is safe: an invoice that is
already paid answers 200 with already_paid: true and settles nothing.
When the settlement can be named, the response carries
settlement_reference. Treat it as optional even on a settling response.
The payment.methods array on the confirm response lists the methods this
environment accepts; a value outside that list is rejected with 400.
Authorizations
Biscuit-based bearer token. Obtain tokens from the Adaptyv Portal or via the /tokens endpoint. Tokens encode organization membership and role-based capabilities; the API verifies the token's cryptographic signature and authorization claims before processing requests. Use /tokens/attenuate to create restricted tokens for delegation.
Headers
Settlement method: mpp-spt or x402-exact. Omit to read the current invoice state and pay via the hosted URL instead. The methods an environment accepts are listed in payment.methods on the confirm response.
Path Parameters
Foundry invoice UUID or Stripe invoice ID (in_xxx)
Response
Invoice paid (or already paid)
Response returned by POST /invoices/{invoice_id}/pay.
Reports the invoice after the call, so no follow-up GET is needed. It is
returned for three outcomes, which status and already_paid tell apart:
a settlement this request performed, an invoice that was already paid, and
— when no payment-method header was sent — the current state of an invoice
that is still unpaid and that this call settled nothing on.
A 200 therefore does not by itself mean the invoice is paid. Read
status. The 402 challenge is not this body.
true when the call was a no-op because the invoice was already paid
before this request.
false otherwise — which covers two different outcomes: this request
settled the invoice, or no payment method was selected and the body
reports the invoice's current state without settling. Read status to
tell those apart; false alone does not mean the invoice is paid.
Stripe invoice ID (in_xxx) that was paid.
"in_1OqLk2LkdIwHu7ix6OboRpXl"
Current invoice status after the call. paid on success.
draft, open, paid, void, uncollectible Stripe-hosted invoice URL, when known.
"https://invoice.stripe.com/i/acct_1234/test_5678"
Names what settled this invoice — the on-chain transaction for
x402-exact, or the Stripe PaymentIntent for mpp-spt.
Only a response that performed the settlement can carry it, so it is
absent when already_paid is true and absent from the state read of
an unpaid invoice. Treat it as optional even on a settling response:
when the rail reports nothing this API can name honestly, the field is
omitted rather than guessed at.
Record it when you receive it. Repeating the call afterwards answers
already_paid without the reference, and it is not available from any
other endpoint.
- Option 1
- Option 2