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

# Protocol Detection

> How BoltzPay detects MPP, x402, L402, and hybrid payment formats

When a server returns `402 Payment Required`, it can encode payment information in several different ways. BoltzPay runs three protocol adapters **in parallel** (`Promise.allSettled`): MppAdapter, X402Adapter, and L402Adapter. Adapter priority: MPP > x402 > L402. When multiple protocols are detected, the SDK prefers MPP (IETF track), then x402 (USDC on-chain), then L402 (Lightning). If the preferred protocol's wallet is not configured, the SDK falls back silently to the next available protocol.

## Parallel Detection

```mermaid theme={null}
flowchart TD
    Start["Response: 402 Payment Required"] --> Par["Parallel detection<br/>(Promise.allSettled)"]

    Par --> MPP["MppAdapter.detect()"]
    Par --> X402["X402Adapter.detect()"]
    Par --> L402A["L402Adapter.detect()"]

    MPP --> MPPWWW{"WWW-Authenticate<br/>contains MPP scheme?"}
    MPPWWW -- Yes --> MPPDone["MPP detected<br/>(payment channels)"]
    MPPWWW -- No --> MPPFail["No MPP found"]

    X402 --> H1{"PAYMENT-REQUIRED<br/>header present?"}

    H1 -- Yes --> V2{"Decode as<br/>x402 V2 JSON"}
    V2 -- Success --> Done["x402 V2 detected"]
    V2 -- Fail --> V1H{"Decode as<br/>x402 V1 in header"}
    V1H -- Success --> Hybrid["x402 V1-in-V2 hybrid detected"]
    V1H -- Fail --> WWW

    H1 -- No --> WWW{"WWW-Authenticate<br/>contains x402?"}
    WWW -- Yes --> WWWx402["x402 via WWW-Authenticate"]
    WWW -- No --> Body{"Response body<br/>contains JSON?"}

    Body -- Yes --> V1B{"Parse as<br/>x402 V1 body"}
    V1B -- Success --> V1["x402 V1 detected"]
    V1B -- Fail --> X402Fail["No x402 found"]

    Body -- No --> X402Fail

    L402A --> L402WWW{"WWW-Authenticate<br/>contains L402 / LSAT?"}
    L402WWW -- Yes --> L402Done["L402 detected<br/>(macaroon + invoice)"]
    L402WWW -- No --> L402Fail["No L402 found"]

    MPPFail --> Pass
    X402Fail --> Pass
    L402Fail --> Pass
    Pass{"All adapters<br/>failed?"}
    Pass -- Yes --> Passthrough["Passthrough<br/>(regular 402)"]

    style MPPDone fill:#365314,stroke:#84cc16,color:#fff
    style Done fill:#365314,stroke:#84cc16,color:#fff
    style Hybrid fill:#365314,stroke:#84cc16,color:#fff
    style WWWx402 fill:#365314,stroke:#84cc16,color:#fff
    style L402Done fill:#365314,stroke:#84cc16,color:#fff
    style V1 fill:#365314,stroke:#84cc16,color:#fff
    style Passthrough fill:#7f1d1d,stroke:#f87171,color:#fff
```

## How It Works

The SDK launches all three adapters in parallel via `Promise.allSettled()` in the protocol router. Each adapter independently probes the URL, inspects the 402 response, and reports whether it can handle it.

### MppAdapter Detection

The MppAdapter checks the `WWW-Authenticate` header for an MPP scheme. MPP uses challenge-response authentication with payment methods (Tempo, Stripe, Visa).

```
WWW-Authenticate: MPP method="tempo" amount="1000000" ...  --> MPP
```

The adapter parses all MPP challenges and selects the best method based on configured wallets and the `mppPreferredMethods` config.

### X402Adapter Detection

The X402Adapter checks three locations in cascade:

**1. PAYMENT-REQUIRED Header** -- The standard location for x402 payment data. The adapter first tries to decode it as **V2 JSON** (the current spec). If that fails, it tries **V1 format** -- some servers send V1-encoded data inside the V2 header. This V1-in-V2 hybrid is rare but exists in the wild (e.g., emc2ai).

```
PAYMENT-REQUIRED: {"x402Version":2,"accepts":[...]}   --> V2
PAYMENT-REQUIRED: {"x402Version":1,"payload":"..."}    --> V1-in-V2 hybrid
```

**2. WWW-Authenticate Header (x402 only)** -- If no `PAYMENT-REQUIRED` header is found, the adapter checks `WWW-Authenticate` for an x402 challenge. It only matches the `x402` scheme and ignores L402/LSAT challenges.

```
WWW-Authenticate: x402 amount="50000" ...              --> x402
```

**3. Response Body (x402 V1)** -- As a final fallback, the adapter reads the response body and attempts to parse it as x402 V1 JSON.

```json theme={null}
{ "x402Version": 1, "payload": "...", "facilitator": "..." }
```

### L402Adapter Detection

The L402Adapter checks `WWW-Authenticate` for an `L402` or `LSAT` challenge with a macaroon and Lightning invoice. It is a separate adapter that runs independently from X402.

```
WWW-Authenticate: L402 macaroon="..." invoice="lnbc.." --> L402
WWW-Authenticate: LSAT macaroon="..." invoice="lnbc.." --> LSAT (legacy)
```

### Passthrough

If no adapter detects a supported protocol, the SDK treats the response as a regular HTTP 402. No payment is attempted, and the original response is returned to the caller.

## Supported Formats

| Format            | Adapter     | Location                                      | Example Server       |
| ----------------- | ----------- | --------------------------------------------- | -------------------- |
| MPP               | MppAdapter  | `WWW-Authenticate` header                     | mpp.dev endpoints    |
| x402 V2           | X402Adapter | `PAYMENT-REQUIRED` header                     | invy.bot, polymarket |
| x402 V1-in-V2     | X402Adapter | `PAYMENT-REQUIRED` header (V1 payload inside) | emc2ai               |
| x402 via WWW-Auth | X402Adapter | `WWW-Authenticate` header                     | 402payment-test      |
| x402 V1 body      | X402Adapter | Response body JSON                            | nickeljoke (testnet) |
| L402 / LSAT       | L402Adapter | `WWW-Authenticate` header                     | satsapi.dev          |

## Why Parallel?

The x402 ecosystem is young. Servers implement different spec versions and sometimes mix formats. By running all three adapters in parallel, BoltzPay maximizes compatibility and speed without requiring any configuration from the user. Your agent calls `fetch()` and the SDK figures out the rest.

## Wallet-Aware Fallback

After detection, the SDK sorts results by priority (MPP > x402 > L402) and filters by configured wallets. If an endpoint supports both MPP and x402:

* With a Tempo wallet configured: MPP is used
* With only Coinbase credentials: x402 is used
* With both: MPP is preferred (higher priority)
* With neither: an actionable error lists detected protocols and required wallet types

```
Endpoint supports MPP (tempo, stripe) and x402 (coinbase).
Configure at least one wallet.
```

## Next Steps

* [How It Works](/concepts/how-it-works) -- the full payment flow from probe to response
* [Budget & Safety](/concepts/budget-safety) -- what happens after detection, before payment
