A machine-readable HTTP 402 gateway that lets publishers charge AI agents for content.
Built at the Founders Hackathon, Hamburg, April 2026, by Levin Wilke and Javier de Golferichs García (AI Beavers).
AI agents increasingly consume paid content at machine speed, and publishers have no machine-readable way to charge them. A login page and a checkout form are not answers to a client that cannot log in, so the practical options today are to block agents entirely or to serve them for free.
This gateway offers a third option. An unpaid machine client receives a structured HTTP 402 Payment Required challenge it can parse, pay, and retry against, with no content leaked before payment. A thin MCP server sits on the agent side as a wallet, so an autonomous client can complete the flow within a bounded budget.
Agent / Scraper → Gateway (402 or grant check) → Protected content
↑
Payment webhook ← Mock / Mollie provider
↑
Payment MCP (wallet tools)
- Agent requests a protected resource with no grant. Gateway answers 402, revealing nothing of the content.
- The 402 carries the challenge as JSON (
agent_paywall_version,accepts,retry_with) plus aPAYMENT-REQUIREDheader with the base64-encoded challenge. - Agent pays through its wallet tools. The gateway verifies with the payment provider.
- Gateway issues an Ed25519-signed JWT access grant, scoped to the resource path, with a TTL and JTI-keyed quota.
- Agent retries with the grant and receives 200 plus the content, until the quota is spent.
Every access decision is appended to an in-region, append-only audit ledger.
Prerequisites: Go 1.22+. Optionally a Mollie test API key for real payment flows.
go mod tidy
mkdir -p bin
go build -o bin/gateway ./cmd/gateway
go build -o bin/payment-mcp ./cmd/payment-mcp
cp config.json.example config.json
./bin/gatewayThen, in a second terminal, the agent-side wallet:
./bin/payment-mcp# 1. No grant → 402, no content leakage
curl -i http://localhost:3001/api/premium-report
# 2. Initiate a payment
curl -s -X POST http://localhost:3001/pay/initiate \
-H 'Content-Type: application/json' \
-d '{"resource_path":"/api/premium-report","amount":"0.50","currency":"EUR"}'
# 3. Poll for the grant (mock provider auto-completes in ~1s)
curl -s 'http://localhost:3001/grants/verify?payment_id=PAYMENT_ID'
# 4. Retry with the grant → 200 + content
curl -s http://localhost:3001/api/premium-report \
-H 'PAYMENT-GRANT: ACCESS_GRANT_TOKEN'A browser demo of a publisher site, Examplepedia, runs at http://localhost:3001/demo.
Scripted walkthroughs, including the four-window live demo, are in DEMO.md.
Register the wallet as an MCP server. In Cursor's MCP settings:
{
"mcpServers": {
"agentic-paywall-wallet": {
"command": "/absolute/path/to/bin/payment-mcp",
"env": {
"GATEWAY_URL": "http://localhost:3001",
"PAYMENT_PROVIDER": "mock"
}
}
}
}Then prompt the agent:
Fetch the market summary at http://localhost:3001/api/premium-report. If you receive a 402 payment required response, use your wallet tools to pay and obtain an access grant, then retry the request with the grant to retrieve the content.
| Tool | Purpose |
|---|---|
get_wallet_allowance |
Check remaining daily EUR budget |
execute_paywall_payment |
Parse a 402 challenge and pay via the gateway |
verify_transaction_status |
Poll until the access grant is ready |
Spending is bounded by wallet.daily_budget, and payments above wallet.auto_pay_threshold require an explicit approval on stderr.
The gateway serves a live, machine-readable residency statement:
curl http://localhost:3001/.well-known/data-residencyIt reports EU region processing, the configured sub-processors, raw_ip_retained: false and cross_border_transfer: false. Runtime access decisions append to ledger/events.jsonl.
The point is that a client can verify these properties rather than trust a privacy policy that asserts them.
Access grants are Ed25519-signed JWTs. The public key is served so verification can happen without calling back to the gateway:
curl http://localhost:3001/.well-known/agent-paywall-key| Field | Description |
|---|---|
provider |
mock (default) or mollie |
gateway.grant_private_key_path |
Ed25519 private key path; generated on first boot |
gateway.grant_quota |
Content requests allowed per grant |
ledger.path |
In-region append-only JSONL audit ledger |
data_residency.region |
Must be EU-prefixed, e.g. eu |
demo.enable_test_completion |
Enables /pay/complete-test for local demos |
wallet.daily_budget |
MCP daily EUR spend limit |
wallet.auto_pay_threshold |
Payments above this require stderr Y/N approval |
Environment overrides: GATEWAY_URL, PAYMENT_PROVIDER, CONFIG_PATH, MOLLIE_API_KEY, LEDGER_PATH, GRANT_PRIVATE_KEY_PATH, GRANT_QUOTA, DEMO_ENABLE_TEST_COMPLETION.
export MOLLIE_API_KEY=test_...
export PAYMENT_PROVIDER=mollie
./bin/gateway/pay/complete-test calls Mollie's test-mode completion path, then verifies the payment before a grant is issued.
The protocol surface, in brief:
- 402 responses carry
agent_paywall_version,acceptsandretry_withas JSON, plus aPAYMENT-REQUIREDheader with the base64-encoded challenge. - Access grants are Ed25519-signed JWTs scoped to a resource path, with TTL, JTI-keyed quota tracking, and public-key verification for edge enforcement.
- Grants may be presented in the
PAYMENT-GRANTheader or as anaccess_grantquery parameter.