> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adaptyvbio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pay with x402 (exact)

> Sign an EIP-3009 transferWithAuthorization, send it in the PAYMENT-SIGNATURE header, and let the facilitator verify and settle the USDC transfer on-chain.

# Pay with x402 (`exact`)

Your agent signs an [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009)
`transferWithAuthorization` over
[EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data and sends the
signature. The API recovers the signer, then asks a **facilitator** — Coinbase
CDP — to verify it and broadcast the transfer. The signature is the payment:
there is no deposit address and no card.

Coinbase's
[x402 overview](https://docs.cdp.coinbase.com/x402/welcome) and
[quickstart for buyers](https://docs.cdp.coinbase.com/x402/quickstart-for-buyers)
cover the client side, including the `@x402/fetch` and `@x402/axios` wrappers
and the Go and Python clients that handle the `402` retry for you.

You need a token whose role grants `Invoice:Pay` — **Member**, **Billing**, or
**Admin** — an EOA whose key your agent controls, and that EOA funded with USDC
on the network the challenge names.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant You as Your agent
    participant API
    participant CDP as CDP facilitator
    participant Chain as Base

    You->>API: POST /experiments (X-Adaptyv-Payment-Method: x402-exact)
    API-->>You: experiment id
    Note over API: Adaptyv prices the work
    You->>API: POST /quotes/{quote_id}/confirm
    API-->>You: invoice_id + payment.pay_url
    You->>API: POST /invoices/{invoice_id}/pay (no credential)
    API-->>You: 402 + PAYMENT-REQUIRED header
    Note over You: sign the EIP-3009 authorization
    You->>API: POST /invoices/{invoice_id}/pay (PAYMENT-SIGNATURE: …)
    API->>CDP: verify the signature
    CDP-->>API: verified
    API->>CDP: settle the transfer
    CDP->>Chain: broadcast the transfer
    Chain-->>CDP: tx_hash
    CDP-->>API: receipt
    API-->>You: 200 — paid + settlement_reference (tx_hash)
```

## Create the experiment

```bash theme={null}
curl -X POST "$FOUNDRY_API_URL/experiments" \
  -H "Authorization: Bearer $FOUNDRY_API_TOKEN" \
  -H "X-Adaptyv-Payment-Method: x402-exact" \
  -H "Content-Type: application/json" \
  -d @experiment.json
```

Confirm the quote as usual. The response carries `payment.pay_url` — the invoice
route you settle at.

## Read the challenge

Call `/pay` with the method header and no credential:

```bash theme={null}
curl -i -X POST "$FOUNDRY_API_URL/invoices/$INVOICE_ID/pay" \
  -H "Authorization: Bearer $FOUNDRY_API_TOKEN" \
  -H "X-Adaptyv-Payment-Method: x402-exact"
```

The challenge is in the `PAYMENT-REQUIRED` response header, base64-encoded,
not in the body. Decode it:

```json theme={null}
{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "125000000",
      "payTo": "0x…merchant-eoa…",
      "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "maxTimeoutSeconds": 300,
      "extra": {
        "name": "USD Coin",
        "version": "2",
        "assetTransferMethod": "eip3009"
      }
    }
  ]
}
```

`payTo` is the merchant EOA, not a deposit address. `asset` is the raw ERC-20
contract address, and `network` its CAIP-2 chain id — read both from the
challenge rather than hardcoding them. `extra` carries the token's EIP-712
domain, `name` and `version`.

## Sign the authorization

Build the EIP-712 typed-data message for the token's `transferWithAuthorization`:

* `from` — your EOA.
* `to` — `payTo` from the challenge.
* `value` — the challenge's `amount` verbatim. It is already in the token's base
  units, so do not rescale it; the signed value must equal it exactly.
* `nonce` — a fresh 32-byte random value **you** generate. It is your own
  on-chain replay token; the challenge does not issue one.
* `validAfter`, `validBefore` — a window **you** choose. `validAfter` must be at
  or before now, and `validBefore` no later than `maxTimeoutSeconds` (300
  seconds) from now.

The EIP-712 domain must match the token contract exactly: `name` and `version`
from the challenge's `extra`, the chain id, and the challenge's `asset` as the
verifying contract. The API recovers the signer over the same hash, so a domain
that differs in any field recovers a different address and the payment is
refused.

<Warning>
  Read `name` and `version` from the challenge rather than assuming them. USDC's
  EIP-712 domain is not the same string on every chain, and a wrong domain fails
  as an authorization error with nothing pointing at the cause.
</Warning>

## Retry with the signature

Base64-encode the signed payload as JSON and send it in the
`PAYMENT-SIGNATURE` header:

```bash theme={null}
curl -i -X POST "$FOUNDRY_API_URL/invoices/$INVOICE_ID/pay" \
  -H "Authorization: Bearer $FOUNDRY_API_TOKEN" \
  -H "X-Adaptyv-Payment-Method: x402-exact" \
  -H "PAYMENT-SIGNATURE: $SIGNED_PAYLOAD_B64"
```

The API recovers the signer, checks the recipient, amount, and deadline, then
asks the facilitator to verify. The facilitator is authoritative on balance and
on whether the nonce is already spent. On success it broadcasts the transfer,
and the transaction hash comes back on the `200`:

```json theme={null}
{
  "id": "in_1OqLk2LkdIwHu7ix6OboRpXl",
  "status": "paid",
  "already_paid": false,
  "settlement_reference": {
    "type": "x402_transaction",
    "tx_hash": "0xabc123deadbeef"
  }
}
```

<Note>
  A `not_yet_settled` verdict re-emits the same `402`. That is not a rejection —
  retry with the **same** signature. Re-signing burns the nonce for nothing.
  Every other `402` after you send a signature is final: a recovered signer that
  does not match, a wrong amount or recipient, an expired `validBefore`, or a
  spent nonce. Resending the same signature will not clear any of them — fix the
  cause and sign a corrected authorization, with a fresh nonce. The challenge
  does not change, so reading it again returns the same terms.
</Note>

<Warning>
  This rail has no settlement recovery. If a settling call dies before you read
  its response, check the invoice status and your EOA on Base before signing
  anything else — a transfer that reached the chain but was never recorded looks
  exactly like a rejection, and signing again with a fresh nonce pays twice.
</Warning>
