# `X402.Verify.AuthCaptureEVM`
[🔗](https://github.com/cardotrejos/x402/blob/v0.9.0/lib/x402/verify/auth_capture_evm.ex#L1)

Verification of `auth-capture` payments on EVM networks.

Runs the spec's client-payload and lifecycle-payload checklists at one of
three depths, mirroring `X402.Verify.EVM`:

* `:structural` — shape, scheme, network, `extra`, operator fields,
  method routing, deadlines, collector and token match, amount and fee.
  Needs nothing.
* `:signature` — additionally recomputes the `signatureNonce` and bound
  salt, verifies the client's ECDSA signature (or gates a counterfactual
  ERC-6492 envelope on the factory allowlist), and recovers every
  authorizer signature. Needs the optional `ex_keccak` / `ex_secp256k1`
  dependencies.
* `:full` — additionally cross-checks the chain id, classifies the payer
  (EOA, ERC-1271, counterfactual), checks the payer balance, reads
  `paymentState` for lifecycle preconditions and single-use enforcement,
  and simulates the exact escrow call. Needs `:rpc`.

A level never silently downgrades: a missing dependency or RPC is an
error, not a pass.

## Facilitator policy

The checklist's operator admission depends on facilitator state, passed
as options: `:submitters` (the addresses the facilitator submits from,
for `"delegated"`), `:operators` (the `"custom"` allowlist),
and `:refund_funding` (whether a delegated
refund has a funding agreement). A server-side caller that only wants
the protocol checks leaves `:submitters` unset to skip admission.

Receiver-authorizer delegation is not supported. Completed charges and
lifecycle payloads require an explicit signature. Operator control alone
is not receiver consent. Refund funding remains a separate application
authorization decision, not something inferred from that signature.

Full verification requires EIP-1898 block-hash references. All state
reads use one canonical block after checking the chain, with no fallback
to `latest`. This trusts the RPC; it is not proof of finality.

Capture-plus-void requires `eth_simulateV1` with a block-hash parent and
successful sequential calls. Unsupported RPCs fail closed. Custom
operators have only structural/signature support; full verification
rejects them until their collect outcome assertions are implemented.
Direct callers are subject to a 64 KiB limit per signature and 78 digits
per decimal value, independent of HTTP header limits.

## Results

`{:ok, verification}` describes the operation the payload settles as,
the reconstructed `PaymentInfo` and its hash, the resolved deployment,
the escrow call (`target`, `calldata`), and — for a capture-and-void —
the second leg's `void_calldata`. `{:error, {:invalid, reason}}` carries
a reason atom `reason_string/1` maps onto the spec's wire strings.

# `authorizer`

```elixir
@type authorizer() :: :signed | :none
```

Where an operation's consent comes from.

# `error`

```elixir
@type error() ::
  {:invalid, X402.AuthCapture.reason()}
  | :missing_dependency
  | :rpc_not_configured
  | {:rpc_error, X402.RPC.error()}
  | {:chain_id_mismatch, non_neg_integer(), non_neg_integer()}
```

Why a verification failed.

# `level`

```elixir
@type level() :: :structural | :signature | :full
```

Requested verification depth.

# `signature_type`

```elixir
@type signature_type() :: :eoa | :erc1271 | :erc6492_counterfactual
```

How the client's signature was (or would be) verified.

# `verification`

```elixir
@type verification() :: %{
  operation: X402.AuthCapture.operation(),
  level: level(),
  payer: String.t(),
  flow: X402.AuthCapture.payment_flow(),
  operator_type: X402.AuthCapture.operator_type(),
  method: :eip3009 | :permit2 | nil,
  chain_id: non_neg_integer(),
  deployment: X402.AuthCapture.EVM.deployment(),
  payment_info: X402.AuthCapture.EVM.payment_info(),
  payment_info_hash: String.t() | nil,
  signature_type: signature_type() | nil,
  authorizer: authorizer(),
  amount: non_neg_integer(),
  fee: non_neg_integer() | nil,
  fee_receiver: String.t() | nil,
  target: String.t(),
  submitter: String.t(),
  calldata: binary() | nil,
  void_calldata: binary() | nil,
  payment_state: X402.AuthCapture.EVM.payment_state() | nil
}
```

A successful verification.

# `classify_revert`
*since 0.9.0* 

```elixir
@spec classify_revert(map()) :: atom() | nil
```

Classifies a node revert onto the spec's typed reasons
(`X402.AuthCapture.EVM.classify_revert/1`).

# `reason_string`
*since 0.9.0* 

```elixir
@spec reason_string(X402.AuthCapture.reason()) :: String.t()
```

Converts a reason atom to its canonical wire string
(`X402.AuthCapture.reason_string/1`).

# `validate_requirements`
*since 0.9.0* 

```elixir
@spec validate_requirements(map()) :: :ok | {:error, error()}
```

Validates static requirements without signing or contacting a node.

Checks amounts, Solidity widths, deployment, operator fields, transfer
method, payment flow and capture mode. Does not establish operator
admission, current deadlines, or onchain funding.

## Examples

    iex> X402.Verify.AuthCaptureEVM.validate_requirements(%{})
    {:error, {:invalid, :scheme}}

# `validate_shape`
*since 0.9.0* 

```elixir
@spec validate_shape(map(), map()) ::
  :ok | {:error, {:invalid, X402.AuthCapture.reason()}}
```

Checks only the payload shape (checklist step 1) — the offline
validation `X402.Scheme.AuthCaptureEVM.validate_payload/3` runs.

# `verify`
*since 0.9.0* 

```elixir
@spec verify(map(), map(), keyword()) :: {:ok, verification()} | {:error, error()}
```

Verifies an `auth-capture` payment or lifecycle payload against its
requirements.

## Options

* `:level` - Verification depth (see the module documentation). The default value is `:full`.

* `:rpc` - An `X402.RPC` configuration. Required for level `:full`.

* `:now` (`t:non_neg_integer/0`) - Unix seconds used by the deadline checks (default: current time).

* `:skew_seconds` (`t:non_neg_integer/0`) - Clock-skew floor for deadline checks. The default value is `6`.

* `:simulate` (`t:boolean/0`) - Whether level `:full` simulates the escrow call. Counterfactual payers
  are always simulated, since the collector deploys the wallet before
  the token validates the signature. The default value is `true`.

* `:verify_chain_id` (`t:boolean/0`) - Whether level `:full` cross-checks `eth_chainId` against the CAIP-2 network. The default value is `true`.

* `:eip6492_allowed_factories` (list of `t:String.t/0`) - Factory addresses (case-insensitive) a counterfactual payer may deploy through. The default value is `[]`.

* `:submitters` - Addresses the facilitator submits from. A `"delegated"` capture
  authorizer must be one of them (`operator_not_admitted` otherwise).
  `nil` skips the admission check for server-side verification. The default value is `nil`.

* `:operators` (list of `t:map/0`) - The `"custom"` operator allowlist: maps with `:address` (or `"*"`)
  and `:operator_type`. Empty admits no contract operator. The default value is `[]`.

* `:refund_funding` (`t:boolean/0`) - Whether a `"delegated"` refund has an out-of-band funding agreement. The default value is `false`.

* `:settlement` (`t:boolean/0`) - Require the completed `charge` form (the `/settle` rule). The default value is `false`.

# `verify_consent`
*since 0.9.0* 

```elixir
@spec verify_consent(map(), map(), keyword()) ::
  {:ok, verification()} | {:error, term()}
```

Verifies a lifecycle consent using pinned EOA/ERC-1271 account rules.

Requires RPC and a capture, void, or refund envelope. Unlike `verify/3` at
full level, this does not require the future escrow state or simulate the
operation. It cannot authorize execution or prove refund liquidity.

---

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