This guide adds an x402 v2 payment gate to an Elixir application.
Install the integrations you use
def deps do
[
{:x402, "~> 0.4"},
{:finch, "~> 0.19"},
{:plug, "~> 1.14"}
]
endFinch and Plug are optional library dependencies, so applications must include
them when using the facilitator client or X402.Plug.PaymentGate.
Start the payment processes
Add Finch, the facilitator client, and an idempotency cache to the application supervision tree:
children = [
{Finch,
name: MyApp.Finch,
pools: %{default: X402.Facilitator.HTTP.secure_pool_opts()}},
{X402.Facilitator,
name: MyApp.Facilitator,
url: "https://facilitator.example.com",
finch: MyApp.Finch},
{X402.Extensions.PaymentIdentifier.ETSCache, name: MyApp.PaymentCache}
]Replace the example URL with the HTTPS endpoint for your facilitator.
Add the Plug
pipeline :paid_api do
plug X402.Plug.PaymentGate,
facilitator: MyApp.Facilitator,
payment_identifier_cache: MyApp.PaymentCache,
routes: [
%{
method: :get,
path: "/api/data",
scheme: "exact",
price: "10000",
network: "eip155:8453",
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
pay_to: "0xYourWalletAddress",
description: "Premium data"
}
]
end
scope "/api" do
pipe_through [:api, :paid_api]
get "/data", DataController, :show
endprice is a string containing atomic token units. For a six-decimal asset,
"10000" represents 0.01 tokens.
An unpaid request receives HTTP 402 with a Base64-encoded v2
PAYMENT-REQUIRED header. For a paid request, the Plug:
- Validates the v2 payload, complete accepted requirement, and extension echo.
- Calls the facilitator's
/verifyendpoint. - Assigns the payload and matched requirements, then runs the protected handler.
- Skips settlement when the handler response is an error.
- Otherwise calls
/settleimmediately before sending the response and addsPAYMENT-RESPONSE.
The handler can read conn.assigns.x402_payment_payload and
conn.assigns.x402_payment_requirements after verification.
Meter an "upto" request
Set scheme: "upto" and advertise the maximum amount with price. The handler
must put the actual charge on the connection before returning its response:
def create(conn, params) do
result = generate(params)
{:ok, conn} =
X402.Plug.PaymentGate.put_settlement_amount(conn, billable_atomic_units(result))
json(conn, %{result: result})
endThe actual amount may be zero but cannot exceed the advertised maximum. Omitting it settles the maximum. See the Plug/Phoenix Integration guide for route, hook, and error details.