Overview
lazysite supports the x402 HTTP payment protocol. Pages can require
payment before being served. When an unpaid request arrives, the
processor returns 402 Payment Required with an X-Payment-Response
header describing payment terms. An x402-compatible wallet or browser
extension reads this header, makes the on-chain payment, and retries
the request with proof.
Payment proof validation is delegated to an upstream proxy. The
processor trusts an X-Payment-Verified header, the same pattern
as X-Remote-User for authentication.
Protecting a page
---
title: Premium Article
payment: required
payment_amount: 0.01
payment_currency: USD
payment_network: base
payment_address: 0x1234...your-wallet-address
payment_description: Access to premium article
---
Front matter keys
payment: required-
Enables the payment gate. Only value is
required. payment_amount-
Amount in human-readable decimal (e.g.
0.01for one cent USD). payment_currency-
Currency code for display. Example:
USD. payment_network-
Blockchain network. Example:
base,ethereum,polygon. payment_address- Recipient wallet address.
payment_asset- Token contract address. Defaults to USDC on the specified network if not set.
payment_description- Optional description shown to the payer.
Member bypass
Members in specified groups skip payment entirely. Add auth_groups:
to the payment-gated page:
---
title: Members Content
payment: required
payment_amount: 0.01
payment_currency: USD
payment_network: base
payment_address: 0x1234...
auth_groups:
- members
- sponsors
---
Authenticated users in members or sponsors see the content
without paying. All other users (including unauthenticated) see the
402 payment page. On a paid page this is what auth_groups means; on
any other page it makes the page a signed-in page for those groups.
Custom 402 page
Create 402.md in the docroot. These TT variables are available:
[% payment_amount %]- amount from front matter[% payment_currency %]- currency from front matter[% payment_network %]- network from front matter[% payment_address %]- wallet address[% payment_description %]- description text
If 402.md does not exist, a minimal built-in page is shown.
TT variables on paid pages
After payment is verified:
[% payment_paid %]- 1 if payment proof verified[% payment_payer %]- payer wallet address if available[% payment_bypassed %]- 1 if access granted via group membership[% payment_amount %]- amount from front matter[% payment_currency %]- currency from front matter[% payment_address %]- wallet address
x402 response header
The X-Payment-Response header returned with 402 responses contains
JSON:
{
"version": "1.0",
"accepts": [{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "10000",
"to": "0x1234...",
"asset": "0x...",
"extra": {
"name": "USDC",
"version": "1"
}
}]
}
maxAmountRequired is in the asset's smallest unit (USDC has 6
decimals, so 0.01 USD = 10000).
Upstream payment proxy
In production, configure a payment proxy to:
- Intercept requests with
X-Payment-Proofheader - Validate the on-chain payment
- Set
X-Payment-Verified: 1and optionallyX-Payment-Payer - Forward to the processor
Configure header names in lazysite/lazysite.conf:
auth_proxy_trusted: true
payment_header_verified: X-Payment-Verified
payment_header_payer: X-Payment-Payer
The engine believes these headers only from a proxy it trusts. Set
auth_proxy_trusted: true whenever a proxy supplies them, and make sure the
proxy strips them from incoming requests before setting its own: without the
flag the engine discards them and logs it, because a visitor can send any
header they like.
Demo mode
payment-demo.pl simulates payment via signed cookies for
testing. Not for production use.
Simulate payment:
/cgi-bin/payment-demo.pl?action=pay&page=/premium&amount=0.01
Clear payment:
/cgi-bin/payment-demo.pl?action=unpay&page=/premium
Demo payments expire after 1 hour.
The dev server auto-detects the demo script and routes requests through it when present.
Cache behaviour
Payment-gated pages are never cached to disk and always include
Cache-Control: no-store, private. This prevents paid content from
being served without payment verification.
Further reading
- Authentication - auth groups used for member bypass
- Payment feature reference