Stateless Settlement-Gated HTTP
Per-request micropayment-gated API access using Bitcoin SV settlement. No accounts. No sessions. No trust. Every request produces cryptographic proof of consumption — independently verifiable, on-chain, and immutable.
What is x402-BSV
Cryptographically verifiable usage metering for HTTP APIs and machine-to-machine systems, using BSV settlement.
x402-BSV is a Stateless Settlement-Gated HTTP Protocol. It integrates settlement directly into the HTTP request lifecycle through a structured 402 challenge → proof → retry flow. Every API call produces an independently verifiable on-chain record. The blockchain is used as a proof layer, not a checkout system — commercial billing remains contractual and off-chain, exactly like AWS or any other cloud provider.
The Problem
Trust-Based Reconciliation
Providers meter usage internally. Customers must trust the provider's accounting. No independent verification. Disputes require manual audit.
Account Friction
Registration, API keys, rate limits, subscription lock-in, pre-funded accounts. Every integration starts with overhead.
Replay Vulnerability
No cryptographic single-use guarantees. Rate limiting relies on IP or session state. Bypassed with proxies. Stateful servers create bottlenecks.
Dispute Failure
Usage records aren't independently verifiable. Logs diverge. No cryptographic proof of consumption. Small disputes are unviable to resolve.
The x402-BSV Model
An unpaid request receives a deterministic payment challenge. The client constructs a partial transaction spending a nonce UTXO issued in the challenge. A delegator hydrates fees, signs, and returns the completed transaction. The client broadcasts to the network, then resubmits the request with cryptographic proof of settlement. The gatekeeper verifies binding, nonce consumption, and settlement acceptance before delivering the asset.
This preserves HTTP semantics while embedding payment as a deterministic precondition to execution. Every usage event is recorded on-chain — independently auditable by both parties.
What It Is — and Isn't
This Is
This Is Not
Why BSV
The protocol design is blockchain-agnostic at the specification level. It requires deterministic per-request settlement, extremely low fees, high throughput, no mempool games, stateless verification, and unbounded scaling without L2 coordination.
Today, only BSV satisfies these constraints without compromises. Other chains can simulate parts of this model by adding layers of trust and batching. BSV is the only chain that runs it natively — predictable fees (1–50 sats), massive throughput, UTXO proofs mapping directly to usage events, and simple, legally intelligible transactions.
Wire Protocol Specification
X402-BSV-PROOF/1 — the exact wire-level protocol for x402-BSV settlement.
FROZEN
View full protocol specification on GitHub ↗
HTTP Flow
The protocol operates as a six-step cycle within standard HTTP semantics.
Step 1 — Client Makes Unpaid Request
GET /api/expensive-resource HTTP/1.1
Host: api.example.com
Accept: application/json
No payment headers. No authentication.
Step 2 — Server Responds with 402 Challenge
HTTP/1.1 402 Payment Required
X402-Challenge: <base64url(JSON)>
X402-Accept: bsv-tx-v1
Cache-Control: no-store
Challenge JSON
{
"v": "1",
"scheme": "bsv-tx-v1",
"nonce_utxo": {
"txid": "hex_string",
"vout": 0,
"satoshis": 1,
"locking_script_hex": "hex_string"
},
"amount_sats": 37,
"payee_locking_script_hex": "hex_string",
"expires_at": 1735689600,
"domain": "api.example.com",
"method": "GET",
"path": "/api/expensive-resource",
"query": "",
"req_headers_sha256": "hex_string",
"req_body_sha256": "hex_string",
"require_mempool_accept": true,
"confirmations_required": 0
}
"1""bsv-tx-v1"Step 3 — Client Constructs Partial Transaction
The client builds a partial transaction with one input (spending the nonce_utxo) and one output
(paying ≥ amount_sats to payee_locking_script_hex). Miner fee inputs and signatures are missing —
these are added by the delegator.
Step 4 — Client Submits to Fee Delegator
{
"partial_tx": "<hex>",
"nonce_utxo": { "txid": "...", "vout": 0 },
"challenge_sha256": "hex_string"
}
The delegator validates, adds fee inputs, signs its own inputs, and returns the completed transaction. The client then broadcasts to the BSV network.
Step 5 — Client Retries with Proof
GET /api/expensive-resource HTTP/1.1
Host: api.example.com
X402-Proof: <base64url(JSON)>
X402-Tx: <base64(rawtx)>
Proof JSON
{
"v": "1",
"scheme": "bsv-tx-v1",
"txid": "hex_string",
"rawtx_b64": "base64_string",
"challenge_sha256": "hex_string",
"request": {
"domain": "api.example.com",
"method": "GET",
"path": "/api/expensive-resource",
"query": "",
"req_headers_sha256": "hex_string",
"req_body_sha256": "hex_string"
}
}
Step 6 — Server Verifies and Responds
The gatekeeper executes a deterministic 16-step verification sequence:
- Base64url decode proof JSON
- Validate
vandscheme - Recompute
req_body_sha256from actual request body - Recompute
req_headers_sha256from actual request headers - Validate request hashes match
proof.request.* - Recompute
challenge_sha256from stored challenge - Validate
challenge_sha256matches proof - Validate domain/method/path/query match challenge
- Validate
now ≤ expires_at - Decode
rawtx_b64, compute txid, compare toproof.txid - Confirm tx includes input spending
nonce_utxo - Confirm tx includes output paying ≥
amount_sats - Query mempool acceptance
- Verify
client_sig(optional, v1.1) - If all pass →
200 OK - If tx valid but not in mempool →
409 Conflictor202 Accepted
Canonical Hashing Rules
Header Hash (req_headers_sha256)
Allowlist (default): accept, content-type, content-length, x402-idempotency-key, x402-client.
- Lowercase header names
- Trim surrounding whitespace in values
- Collapse internal runs of whitespace to single space
- Sort by header name (lexicographic)
- Join as:
name:value\nfor each header - Compute:
SHA256(utf8(canonical_headers_string))→ hex
Body Hash (req_body_sha256)
SHA256(raw_body_bytes) → hex. If no body: SHA256("") → hex.
Challenge Hash (challenge_sha256)
Serialize challenge JSON using RFC 8785 (JSON Canonicalization Scheme, JCS). Sort object keys lexicographically, no whitespace, deterministic encoding. SHA256(canonical_json_bytes) → hex.
Transaction Constraints
For scheme = "bsv-tx-v1", the transaction must contain:
- Nonce spend — one input spending
nonce_utxofrom challenge - Payee output — one output with locking script matching
payee_locking_script_hex, amount ≥amount_sats - Optional change output(s) — as needed
If require_mempool_accept is true, the gatekeeper verifies mempool visibility independently.
Broadcast origin is irrelevant to correctness. No confirmations required by default.
Acceptance Matrix
| Condition | HTTP Status | Headers |
|---|---|---|
| Valid proof, mempool accepted | 200 OK | X402-Receipt: <hash> |
| Valid proof, mempool pending | 202 Accepted | X402-Status: pending |
| Expired challenge | 402 Payment Required | New X402-Challenge |
| Invalid proof format | 400 Bad Request | — |
| Wrong endpoint/path | 403 Forbidden | — |
| Double-spend (nonce already spent) | 409 Conflict | X402-Status: double-spend |
| Invalid transaction | 402 Payment Required | New X402-Challenge |
| Mempool rejection | 402 Payment Required | New X402-Challenge |
| Insufficient amount | 402 Payment Required | New X402-Challenge |
Error Codes
| Code | Description |
|---|---|
invalid_version | Protocol version not supported |
invalid_scheme | Payment scheme not supported |
invalid_nonce | Nonce UTXO invalid or already spent |
invalid_payee | Payee output doesn't match challenge |
insufficient_amount | Payment amount below minimum |
expired_challenge | Challenge past expiry time |
mempool_rejected | Transaction rejected by mempool |
invalid_binding | Request binding doesn't match |
double_spend | Nonce already spent in different tx |
Architecture
Five strictly separated layers. Each with non-negotiable boundaries. No responsibility blurring.
Component Boundaries
The Gatekeeper handles HTTP semantics and proof validation — it never signs transactions, manages UTXOs, or holds private keys. The Fee Delegator handles transaction construction and fee sponsorship — it never parses HTTP, evaluates expiry timestamps, or performs business logic. The BSV Network enforces UTXO single-spend globally — it knows nothing about x402.
Trust Boundaries
| Boundary | Type | Description |
|---|---|---|
| Client ↔ Network | Settlement | Client broadcasts completed transaction. Client is the settlement actor. |
| Delegator ↔ Client | Construction | Delegator validates partial tx, adds fee inputs, signs, returns completed tx. |
| Gatekeeper ↔ Network | Verification | Gatekeeper verifies mempool visibility independently. Broadcast origin irrelevant. |
Economics & Security
Operationally survivable by design — bounded costs, layered abuse prevention, deterministic failure modes.
Per-Request Cost Breakdown
| Component | Cost | Notes |
|---|---|---|
| Nonce UTXO | 1 sat | One-time, can be reclaimed if unused |
| Miner fee | 1–50 sats | Typical BSV fees |
| Mempool query | Negligible | Local node |
| Total per request | ~2–51 sats | ~$0.0001–$0.005 |
Infrastructure costs: $50–500/month depending on scale (node + servers).
Funding Modes
The protocol is invariant across modes. Only the funding source changes.
| Component | Mode 1: Self-Funded | Mode 2: Sponsored |
|---|---|---|
| Nonce UTXO | Gateway | Gateway |
| Miner fee | Client | Delegator |
| Service output | Client | Delegator |
| Use case | End state — fully atomic | Onboarding — zero client friction |
Threat Model
Replay Attacks
Nonce UTXO can only be spent once (network-enforced). Request binding ensures proof matches exact parameters. Cross-endpoint reuse fails validation.
Abuse / DoS
Rate limiting per IP/endpoint. Fee caps per transaction. Nonce pool size limits. Daily delegation budgets. Worst case at 1M requests: ~$500.
Mempool Uncertainty
Two-node quorum acceptance (recommended). First-seen LRU cache (TTL minutes). Conflicting nonce spends rejected immediately.
Operator Misbehaviour
Gatekeeper cannot sign transactions. Delegator doesn't understand HTTP. All proofs are independently verifiable on-chain. Boundaries prevent manipulation.
Expiry Races
Checked at both challenge generation and proof verification. Reasonable expiry windows (minutes, not seconds). Client can request new challenge.
Binding Bypass
Canonical header hashing (deterministic). Body hash included. Method, path, query bound. Verification recomputes from actual request.
Abuse Prevention Controls
| Control | Mechanism | Default |
|---|---|---|
| Rate limiting | Per IP/endpoint, burst allowance | 60–100 req/min |
| Fee caps | Per transaction + daily/weekly budgets | 100 sats/tx, 10M sats/day |
| Nonce pool | Pre-mint pool with auto-replenish | 100K–1M nonces |
| Dynamic pricing | Abuse detection increases price | 2x at 1K req, 10x at 10K |
| Budget exhaustion | 503 Service Unavailable + Retry-After | Hard stop at daily cap |
Getting Started
Run the reference implementation locally in under five minutes.
Prerequisites
- Go 1.21+ (for gateway server and delegator)
- Node.js 20+ (for client SDK)
- Redis (optional — for persistent UTXO pool state)
- Docker (optional — for containerized deployment)
Quick Start
# Clone the reference implementation
git clone https://github.com/merkleworks/x402-bsv.git
cd x402-bsv
# Generate keys and configure
make setup
# Start the gateway (gatekeeper + delegator + demo API)
make demo
# In another terminal — make a paid request
make client
make setup generates BSV keypairs and creates a .env file.
make demo starts the full stack on localhost. make client executes the
complete 402 challenge → proof → response cycle.
Client SDK (TypeScript/Node.js)
The @merkleworks/x402-client package is a drop-in fetch() replacement
that handles the x402 flow transparently. It performs the original request, intercepts 402 responses,
forwards the challenge to the gateway, and retries with proof — in a single call.
npm install @merkleworks/x402-client
import { X402Client } from '@merkleworks/x402-client';
const client = new X402Client({
gatewayUrl: 'https://gateway.example.com',
});
// Drop-in fetch replacement — handles 402 transparently
const response = await client.fetch('https://api.example.com/expensive-resource');
const data = await response.json();
Configuration Reference
| Variable | Description | Default |
|---|---|---|
X402_LISTEN_ADDR | Gateway HTTP listen address | :8402 |
X402_HD_SEED | BIP32 HD wallet seed (hex) | Generated by setup |
X402_NONCE_POOL_SIZE | Pre-minted nonce pool target | 1000 |
X402_FEE_CAP_SATS | Maximum fee per transaction | 100 |
X402_DAILY_BUDGET_SATS | Daily delegation budget | 10000000 |
X402_BROADCASTER | Broadcast backend (arc, woc, mock) | arc |
X402_REDIS_URL | Redis connection string (optional) | In-memory pools |
X402_CHALLENGE_TTL | Challenge expiry duration | 300s |
Docker Deployment
# Build and run with Docker Compose
docker compose up -d
# Or build individual images
docker build -t x402-gateway -f Dockerfile.server .
docker build -t x402-delegator -f Dockerfile.delegator .
API Reference
Endpoints exposed by the gateway and delegator. Download the Postman collection to test these endpoints directly.
Protected Endpoints (any path behind the gatekeeper middleware)
Any endpoint behind the x402 middleware returns 402 Payment Required with
X402-Challenge header on unpaid requests. Paid requests include
X402-Proof and X402-Tx headers.
Fee Delegator
| Method | Path | Description |
|---|---|---|
POST | /delegate/x402 | Submit partial tx for fee delegation and signing |
Dashboard API
| Method | Path | Description |
|---|---|---|
GET | /api/v1/stats | Pool statistics, request counts, revenue |
GET | /api/v1/events/stream | SSE stream of real-time gateway events |
GET | /api/v1/treasury | Treasury UTXO state and settlement tracking |
GET | /api/v1/broadcast/health | Broadcaster backend health status |
GET | /api/v1/config | Current gateway configuration |
Project Structure
Go monorepo with TypeScript client SDK and React dashboard.
x402-bsv/
├── cmd/
│ ├── server/ # Main gateway binary
│ ├── delegator/ # Standalone fee delegator
│ ├── keygen/ # Key generation utility
│ ├── setup/ # Initial setup tool
│ └── client/ # CLI test client
├── internal/
│ ├── gatekeeper/ # 402 middleware, challenge gen, proof verification
│ ├── delegator/ # Partial tx validation, fee injection, signing
│ ├── broadcast/ # Multi-backend tx broadcaster (ARC, WoC, Mock)
│ ├── pool/ # UTXO pool management (nonce, fee, payment)
│ ├── challenge/ # Challenge building, canonical hashing
│ ├── treasury/ # Treasury watcher, fanout, sweep, refill
│ ├── replay/ # LRU + TTL replay detection cache
│ ├── hdwallet/ # BIP32 HD key derivation
│ ├── pricing/ # Pluggable pricing (fixed, per-byte)
│ └── dashboard/ # Dashboard API handlers
├── client-js/ # @merkleworks/x402-client (TypeScript)
│ └── src/
│ ├── client.ts # X402Client — drop-in fetch replacement
│ ├── challenge.ts # Challenge parsing, canonical hashing
│ ├── transaction.ts # Partial transaction building
│ ├── proof.ts # Proof header generation
│ ├── delegator.ts # Gateway communication
│ └── broadcaster.ts # ARC broadcast integration
├── dashboard/ # React + TypeScript + Vite
│ └── src/
│ ├── MonitorTab.tsx
│ ├── TreasuryTab.tsx
│ ├── AnalyticsTab.tsx
│ └── SettingsTab.tsx
├── docs/ # Additional documentation
├── Dockerfile.server
├── Dockerfile.delegator
├── docker-compose.yml
├── Makefile
└── go.mod
Governance
Authority hierarchy for specification and implementation.
| Tier | Document | Authority |
|---|---|---|
| 0 | North Star / Constitutional Statement | Foundational vision. Invariants. Non-negotiable boundaries. |
| 0.5 | Adoption Doctrine | Funding mode definitions. Economic narrative. |
| 1 | Protocol Spec (Wire-Level) | Normative wire contract. Scheme, challenge, proof, hashing, verification. |
| 2 | Implementation Spec | Reference implementation mapping. Delegator contract. |
| 3 | Architecture / Models | Layer separation. Threat model. Economic model. |
| 4+ | External / Editorial | Whitepapers, READMEs, marketing. Descriptive only. |