# `X402.Plug.Facilitator`
[🔗](https://github.com/cardotrejos/x402/blob/v0.9.0/lib/x402/plug/facilitator.ex#L2)

Plug scaffold exposing one or more facilitator engines as the
facilitator HTTP API.

Serves the x402 v2 facilitator endpoints over any Plug-compatible server
(Bandit, Cowboy, or mounted inside a Phoenix endpoint):

| Endpoint                   | Behaviour                                          |
| -------------------------- | -------------------------------------------------- |
| `POST /verify`             | the matching engine's `verify/3`                   |
| `POST /settle`             | the matching engine's `settle/3`                   |
| `GET /supported`           | the engines' `supported/1`, merged                 |
| `GET /discovery/resources` | `404` — bazaar discovery serving is not included   |

## Usage

    {:ok, engine} =
      X402.Facilitator.Engine.new(
        rpc: rpc,
        signer: signer,
        networks: ["eip155:84532"]
      )

    children = [
      {Finch, name: MyApp.Finch},
      {Bandit, plug: {X402.Plug.Facilitator, engine: engine}, port: 4022}
    ]

Mount the plug at the root of its listener (or behind a `forward` that
strips the prefix): it answers `404` for paths it does not serve.

## Multiple engines

A facilitator serving several chain families passes `:engines` instead
of `:engine` — for example an EVM `X402.Facilitator.Engine` next to an
SVM `X402.Facilitator.SVMEngine`:

    {X402.Plug.Facilitator, engines: [evm_engine, svm_engine]}

Exactly one of `:engine` and `:engines` must be given. `POST /verify`
and `POST /settle` dispatch to the first engine whose `supported/1`
kinds contain the request's `paymentRequirements` `(scheme, network)`
pair; when none matches, the request is answered with a `200`
protocol rejection (`unsupported_scheme`, or `invalid_network` when
some engine serves the scheme on other networks). `GET /supported`
merges the engines' responses — kinds concatenated, extensions
unioned, signer families merged. Any struct whose module exports
`verify/3`, `settle/3`, and `supported/1` with the engine wire
contract can be listed.

## Extension responses sidechannel

An engine's `verify/3` or `settle/3` may return
`{:ok, wire_response, extension_responses}` where the third element is
a map of extension outcomes keyed by extension name (for example
`%{"bazaar" => %{"status" => "success"}}`). The plug encodes it into the
`EXTENSION-RESPONSES` response header (x402 v2 §7.2.1, see
`X402.ExtensionResponses`), keeping it out of the JSON body that
resource servers may relay to buyers. The built-in engines return the
two-element form.

## Request/response contract

`POST /verify` and `POST /settle` require exactly the v2 facilitator
wire object — `{"x402Version": 2, "paymentPayload": {...},
"paymentRequirements": {...}}` — and reject anything else with `400`.
Following the facilitator API convention, protocol-level rejections are
**200** responses (`{"isValid": false, ...}` / `{"success": false,
...}`); non-2xx statuses are reserved for transport-level problems:

| Status | Meaning                                                        |
| ------ | -------------------------------------------------------------- |
| `200`  | Engine verdict (including invalid / failed payments)           |
| `400`  | Malformed body: bad JSON or not the v2 wire object             |
| `401`  | Missing/wrong bearer token (when `:auth_token` is configured)  |
| `404`  | Unknown path (including `/discovery/resources`)                |
| `405`  | Known path, wrong method                                       |
| `413`  | Body larger than `:max_body_bytes`                             |
| `500`  | Engine infrastructure error — opaque body, details are logged  |

## Authentication

The optional `:auth_token` enables a minimal bearer-token check
(constant-time comparison) on every endpoint. It is a convenience for
private deployments — put real authentication, TLS termination, and
rate limiting in front of a production facilitator.

# `options`

```elixir
@type options() :: %{
  engines: [struct()],
  auth_token: String.t() | nil,
  max_body_bytes: pos_integer()
}
```

Validated plug options.

# `call`
*since 0.6.0* 

```elixir
@spec call(Plug.Conn.t(), options()) :: Plug.Conn.t()
```

Dispatches a facilitator API request — see the module documentation for
the endpoint and status contract.

# `init`
*since 0.6.0* 

```elixir
@spec init(keyword()) :: options()
```

Validates the plug options.

Exactly one of `:engine` and `:engines` must be given; both are
normalized to a list of engines internally.

## Options

* `:engine` - A single `X402.Facilitator.Engine` configuration built with
  `Engine.new/1`. Exactly one of `:engine` or `:engines` must be
  given.

* `:engines` - A non-empty list of engine structs (`X402.Facilitator.Engine`,
  `X402.Facilitator.SVMEngine`, or any struct whose module exports
  `verify/3`, `settle/3`, and `supported/1`), dispatched by the
  request's `(scheme, network)`. Exactly one of `:engine` or
  `:engines` must be given.

* `:auth_token` - Optional bearer token required on every request (compared in
  constant time). `nil` disables authentication — front a production
  deployment with real auth instead. The default value is `nil`.

* `:max_body_bytes` (`t:pos_integer/0`) - Maximum accepted request body size, consistent with the SDK's 8KB
  encoded-header caps. Larger bodies answer `413`. The default value is `8192`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
