# `X402.Hooks.RequestContext`
[🔗](https://github.com/cardotrejos/x402/blob/v0.9.0/lib/x402/hooks/request_context.ex#L1)

Context of a protected request passed to the resource-server lifecycle hooks.

`X402.Plug.PaymentGate` and `X402.MCP.Server` build one of these for every
request that reaches a gated route or paid tool and hand it to the optional
`c:X402.Hooks.on_protected_request/2` and
`c:X402.Hooks.on_verified_payment_canceled/2` callbacks.

* `:transport` — `:http` (Plug gate) or `:mcp` (tool call).
* `:conn` — the `Plug.Conn` for HTTP requests, `nil` for MCP.
* `:request` — the MCP tool-call params map, `nil` for HTTP.
* `:route` — the gate's compiled route (HTTP) or the paid-tool
  configuration (MCP), as an opaque map.
* `:method` / `:path` / `:path_params` — the HTTP request method, decoded
  path, and the values captured by `:param` segments of the route pattern.
* `:tool` — the MCP tool name.
* `:requirements` — the string-keyed `PaymentRequirements` maps the
  request advertises (`PaymentRequired.accepts`). A `on_protected_request`
  hook may replace this list to change the terms for the current request.
* `:extensions` — the `PaymentRequired.extensions` map advertised to the
  client, which the hook may replace as well.
* `:payload` / `:matched_requirements` — the decoded `PaymentPayload` and
  the requirements it matched; only set once a payment has been verified
  (that is, in `on_verified_payment_canceled`).

# `t`

```elixir
@type t() :: %X402.Hooks.RequestContext{
  conn: term() | nil,
  extensions: map(),
  matched_requirements: map() | nil,
  method: atom() | nil,
  path: String.t() | nil,
  path_params: %{optional(String.t()) =&gt; String.t()},
  payload: map() | nil,
  request: map() | nil,
  requirements: [map()],
  route: map() | nil,
  tool: String.t() | nil,
  transport: transport()
}
```

# `transport`

```elixir
@type transport() :: :http | :mcp
```

Transport the protected request arrived on.

# `new`
*since 0.9.0* 

```elixir
@spec new(keyword()) :: t()
```

Builds a request context from a keyword list of fields.

Unknown keys are ignored so callers can pass through transport metadata.

## Examples

    iex> context = X402.Hooks.RequestContext.new(transport: :mcp, tool: "search", requirements: [%{"scheme" => "exact"}])
    iex> {context.transport, context.tool, context.requirements}
    {:mcp, "search", [%{"scheme" => "exact"}]}

    iex> X402.Hooks.RequestContext.new([]).path_params
    %{}

# `valid?`
*since 0.9.0* 

```elixir
@spec valid?(term()) :: boolean()
```

Checks that a value returned by a hook is a well-formed request context.

A hook may replace `:requirements` (a non-empty list of maps) and
`:extensions` (a map) but nothing else is validated: the transports treat
every other field as informational.

## Examples

    iex> context = X402.Hooks.RequestContext.new(requirements: [%{"scheme" => "exact"}])
    iex> X402.Hooks.RequestContext.valid?(context)
    true

    iex> X402.Hooks.RequestContext.valid?(X402.Hooks.RequestContext.new(requirements: []))
    false

    iex> X402.Hooks.RequestContext.valid?(%{requirements: [%{}]})
    false

---

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