Let us begin with a very simple question:
How should a machine buy one useful computation from another machine?
Not a monthly subscription. Not a user account. Not a dashboard. One operation. One price. One result.
HTTP has had a status code for this since the beginning:
402 Payment Required
For decades, it was almost entirely dormant.
x402 gives it an actual job.
Suppose an agent wants a resource.
It sends an ordinary HTTP request:
POST /sql-plan-doctor
It does not yet include payment.
The server responds:
402 Payment Required
But this is not merely a rejection. The response contains a complete payment specification:
- the blockchain network,
- the payment asset,
- the amount,
- and the recipient wallet.
For example:
network: eip155:8453
asset: USDC
amount: 20000
payTo: 0x...The network identifier eip155:8453 means Base mainnet. The amount 20000 means 20,000 atomic USDC units.
USDC has six decimal places, so:
20,000 atomic units = 0.020000 USDC
The client now signs an EIP-712 authorization agreeing to those exact terms. It retries the same request and includes the signed authorization:
PAYMENT-SIGNATURE: ...
The server sends that proof to a facilitator.
The facilitator verifies the authorization and performs or coordinates settlement. If the proof is valid, the server executes the operation and returns the artifact.
The complete cycle is therefore:
request → 402 → sign → retry → verify → execute → 200
Notice what is missing.
There is no user registration. There is no API key. There is no prepaid balance. There is no monthly invoice. There is no dashboard.
The server does not need to know who the buyer is. It needs to know only that the payment authorization is valid and bound to the requested operation.
That is the essential idea.
Now consider the operations we want to sell.
A client submits:
- a source-code repository,
- a SQL query and execution plan,
- a domain name,
- a database migration,
- a proposed code patch,
- or a collection of genealogical records.
The service performs a difficult but bounded computation, often involving a frontier model, and returns one structured artifact:
- an architectural model,
- a query correction,
- a migration-risk report,
- a buyer list,
- an evidence proof,
- or a machine-readable verdict.
The important unit is not access for one month.
The important unit is:
one input → one operation → one artifact
Suppose the artifact is worth 25 cents.
What would conventional SaaS require?
- Open a website.
- Create an account.
- Verify an email address.
- Create an API key.
- Enter a credit card.
- Purchase credits or accept monthly billing.
- Store and secure the credentials.
- Finally make the request.
The administrative machinery costs more than the transaction it is supporting.
That is the central mismatch.
The buyer may not even be a human. It may be an autonomous agent executing a larger workflow. It does not want a relationship with the vendor. It wants a result now, inside the current HTTP interaction.
When the operation costs between five cents and two dollars, conventional account infrastructure becomes friction of the wrong scale.
x402 reduces the commercial interaction to the scale of the computation.
Not every endpoint should be monetized independently.
A good x402 operation has four properties:
- The backend work is nontrivial.
- The output is a bounded artifact.
- The operation has a meaningful per-call price.
- An agent can use it without a dashboard.
Several products fit this structure naturally.
Input:
- source repository
Output:
- architectural model
- hidden couplings
- failure modes
- commit-sized implementation specifications
Price: $0.50–$20.00
Input:
- domain name
Output:
- probable buyers
- commercial uses
- positioning
- price band
Price: $0.25–$2.00
Input:
- database migration
- schema context
- deployment constraints
Output:
- risk analysis
- locking behavior
- rollback limits
- phased alternative
Price: $0.10–$1.00
Input:
- SQL query
EXPLAINorEXPLAIN ANALYZEoutput- schema metadata
Output:
- dominant bottleneck
- reasoning trace
- index or query correction
Price: $0.05–$0.50
Input:
- records supporting a proposed relationship
Output:
- proof statement
- evidence classification
- conflicts
- confidence assessment
Price: $0.25–$2.00
Input:
- task
- candidate patch
- test output
- evaluation policy
Output:
- machine-readable verdict
- failure classification
- supporting observations
Price: $0.05–$0.25
These are not merely model calls wrapped in cryptocurrency.
That distinction matters.
The customer is not buying tokens. The customer is buying an artifact with a stable contract.
The internal implementation may change from one model to another. The token count may vary. The service may add static analysis, retrieval, deterministic validation, or caching.
The product remains:
input schema → defined operation → output schema
The artifact is the product.
The model is merely one component of the production machinery.
These operations are also bounded and approximately idempotent in spirit.
That does not necessarily mean every byte of output is identical. A probabilistic model may produce slightly different wording.
It means the semantic contract is stable:
f(x) ≈ y
For the same input x, repeated executions should produce artifacts belonging to the same useful equivalence class y.
A SQL plan should identify the same dominant bottleneck. A repository analysis should recover approximately the same architectural structure. A genealogy resolver should not reverse its conclusion without new evidence.
This boundedness creates several useful properties:
- per-operation pricing is understandable,
- results can be cached,
- retries can return stored artifacts,
- duplicate payments can be prevented,
- execution can be separated from delivery,
- and completed results can be replayed safely.
These are not secondary optimizations. They are consequences of treating the artifact as the unit of sale.
Now we reach the architecture.
Should we build fifty independent services, each with its own payment handling, facilitator integration, accounting logic, pricing engine, and discovery mechanism?
Certainly not.
The stronger design is:
one paid-operation kernel + many narrow workers
Each product implements only the operation-specific logic.
Conceptually:
type Operation interface {
Name() string
Validate(body []byte) error
Estimate(body []byte) Estimate
Execute(ctx context.Context, body []byte) (Result, error)
}The exact public interface may be smaller, but these are the conceptual responsibilities:
Nameidentifies the operation.Validaterejects malformed or unsupported inputs.Estimatepredicts resource requirements or pricing inputs.Executeperforms the work and returns the artifact.
Everything else belongs to the kernel:
- generate payment requirements,
- return the
402, - bind payment to the request,
- verify the signature,
- coordinate settlement,
- execute exactly once,
- store the result,
- account for cost,
- update pricing,
- expose operational metrics,
- and advertise the route.
The products are separate economically but shared operationally.
One wallet may receive payment for many endpoints. One facilitator may verify many payment authorizations. One registry may advertise many operations.
Each route may still have:
- its own input schema,
- its own output schema,
- its own worker,
- its own price,
- its own cost model,
- and its own discovery metadata.
This is the correct abstraction boundary:
payment mechanics ≠ operation mechanics
Money inside the kernel is represented as micro-USD.
type USD int64with:
1,000,000 micro-USD = $1.00
Therefore:
1 micro-USD = $0.000001
5,000 micro-USD = $0.005
20,000 micro-USD = $0.020
1,000,000 micro-USD = $1.00
Why not use float64?
Because binary floating-point does not represent most decimal fractions exactly.
For example, the decimal value 0.1 does not have a finite binary representation. Arithmetic that appears trivial can accumulate rounding error.
Money requires exact comparisons and deterministic serialization. Integer arithmetic gives us both.
There is an additional advantage here.
USDC also uses six decimal places. Therefore:
1 micro-USD = 1 atomic USDC unit
at a nominal one-dollar USDC valuation.
The framework boundary can therefore use one integer scale for both internal accounting and protocol amounts:
20,000 micro-USD ↔ 20,000 atomic USDC ↔ $0.020000
The mapping is direct, testable, and free from decimal conversion noise.
The protocol still serializes the amount as a string because EVM token amounts are conceptually uint256, while JSON numbers become unsafe above 2^53. A JavaScript client cannot exactly represent every integer beyond that boundary.
Therefore:
{
"amount": "20000"
}is correct, while:
{
"amount": 20000
}establishes a dangerous convention for larger values.
At the framework boundary, the worker can be reduced to one essential method:
type Worker interface {
Execute(
ctx context.Context,
body []byte,
) (Result, error)
}Why []byte?
Because the framework should not know the application's domain types.
The payload might be:
- JSON,
- Protocol Buffers,
- plain text,
- a compressed archive,
- source code,
- or some future binary format.
The payment kernel should not care.
Its responsibility is to transport a paid request to a worker and transport the resulting artifact back to the caller.
A result might be:
type Result struct {
Body []byte
ContentType string
CostUSD cost.USD
Metadata map[string]any
}The fields have distinct purposes:
Bodyis the purchased artifact.ContentTypetells the caller how to interpret it.CostUSDreports the internal execution cost.Metadatasupports discovery, observability, or route-specific details.
Most application workers will use JSON. A generic adapter can preserve type safety without coupling the kernel to those types:
func Adapt[Req any, Resp any](
fn func(context.Context, Req) (Resp, cost.USD, error),
) WorkerThe adapter performs:
bytes → Req → operation → Resp → bytes
and emits:
Content-Type: application/json
The kernel remains byte-oriented. The worker remains type-oriented. Neither layer leaks its concerns into the other.
Let us now follow one request carefully.
The client sends:
POST /v1/sql-plan-doctor
Content-Type: application/json
{
"sql": "SELECT ...",
"plan": "..."
}No payment proof is present.
The route's pricer returns the current amount:
amount := route.Pricer.Get()Suppose:
amount = 20000
The server responds:
402 Payment Required
PAYMENT-REQUIRED: ...
Content-Type: application/jsonThe payment requirements identify:
eip155:8453,- the USDC contract,
"20000",- the receiving wallet,
- and any protocol-specific constraints.
The same terms appear in the response body and the PAYMENT-REQUIRED header.
Why both?
The header participates directly in the machine protocol. The body makes the response inspectable and usable by clients that expose or log structured error bodies.
The client signs an EIP-712 typed-data payload.
The signature is not a vague promise to pay something later. It is an authorization bound to explicit terms.
The client retries the operation:
POST /v1/sql-plan-doctor
PAYMENT-SIGNATURE: ...
Content-Type: application/json
{
"sql": "SELECT ...",
"plan": "..."
}The server calls:
verification, err := facilitator.Verify(ctx, request)A valid result establishes that the supplied authorization satisfies the payment requirements.
But verification alone is not the entire durable protocol.
The kernel must eventually distinguish:
unverified
verified
settlement pending
settled
execution running
completed
failed
Those states become critical when timeouts, retries, crashes, or facilitator ambiguity occur.
Once payment is valid and settlement policy permits execution:
result, err := worker.Execute(ctx, body)The route knows its revenue:
revenue = 20,000 micro-USD
The worker reports its cost:
cost = 8,000 micro-USD
The realized gross margin is:
(20,000 − 8,000) / 20,000 = 0.60
or 60%.
The kernel reports that observation to the pricer:
pricer.Report(revenue, result.CostUSD)The server responds:
200 OK
Content-Type: application/jsonwith the purchased artifact.
The entire commercial transaction has occurred inside an ordinary HTTP exchange.
Pricing should not be embedded as a route constant.
It is a policy:
type Pricer interface {
Get() int64
Report(revenue, costUSD cost.USD)
}A fixed pricer is appropriate when execution cost is stable or irrelevant.
For example:
FixedPricing(0.05)might produce:
50,000 atomic USDC units
The implementation ignores cost feedback:
func (p *FixedPricer) Report(
revenue cost.USD,
expense cost.USD,
) {
}This is suitable for:
- deterministic local computation,
- cached datasets,
- fixed-cost validation,
- lightweight transforms,
- or deliberately promotional pricing.
The invariant is:
P_{t+1} = P_t
Regardless of observed cost, the price does not move.
LLM-backed operations are different.
The cost of analyzing a 500-line repository and the cost of analyzing a 50,000-line repository may differ by orders of magnitude.
A single fixed price creates one of two failures:
- Large operations are underpriced.
- Small operations are priced out.
Dynamic pricing uses measured execution cost to move the route toward a target margin.
Let:
Cbe execution cost,Pbe price,mbe the target gross margin.
By definition:
m = (P − C) / P
Rearrange:
mP = P − C
C = P(1 − m)
Therefore the price required to achieve margin m is:
P* = C / (1 − m)
Suppose the execution cost is:
C = $0.008
and the target margin is:
m = 0.60
Then:
P* = 0.008 / (1 − 0.60) = 0.008 / 0.40 = 0.020
The target price is two cents.
However, we should not immediately jump the public price to the latest observed target. One unusually large request could create a violent price swing.
Instead, use an exponential moving average:
P_{t+1} = α·P* + (1 − α)·P_t
with:
α = 0.2
Suppose the current price is:
P_t = $0.015
and the newly computed target is:
P* = $0.020
Then:
P_{t+1} = 0.2(0.020) + 0.8(0.015)
= 0.004 + 0.012
= $0.016
The route moves toward the observed cost structure without allowing one request to dominate the price.
A floor is also enforced:
P ≥ $0.005
The floor covers fixed overhead and prevents the route from drifting into economically meaningless prices.
This pricing mechanism is not magic. It is a feedback controller.
Its inputs are:
observed cost
observed revenue
target margin
current price
Its output is:
next advertised price
Different policies can implement the same interface:
- cost-plus pricing,
- size-aware preflight pricing,
- demand-responsive pricing,
- externally controlled pricing,
- customer-tier pricing,
- or market-clearing auctions.
The kernel does not change. Only the controller changes.
A perfect endpoint that nobody can find has an expected revenue of zero.
Therefore paid operations need discovery.
A service may advertise its endpoints to a registry. Each listing can include:
- public URL,
- operation name,
- description,
- input schema,
- output schema,
- tags,
- accepted network,
- accepted asset,
- and current price.
The service is configured with:
- a payment wallet,
- a facilitator,
- its externally reachable base URL,
- and an optional
Discoverer.
A background heartbeat re-announces the routes periodically:
every 30 minutes:
read current route prices
publish endpoint descriptions
The price must be read from each route's live pricer. Otherwise the registry advertises stale prices while the endpoint demands new ones.
The heartbeat runs until its context is canceled:
for {
select {
case <-ticker.C:
announce()
case <-ctx.Done():
return
}
}Discovery must remain best-effort.
If the registry is unavailable, the paid endpoint should continue serving requests. Registry failure is not payment failure and must not become execution failure.
Therefore:
registry error → log and retry
not:
registry error → terminate service
Workers may optionally implement richer description metadata:
type Describer interface {
Description() Description
}A basic worker remains executable without discovery metadata. A descriptive worker becomes easier for agents to evaluate and select.
This preserves a clean separation:
execution capability ≠ marketing metadata
The current implementation follows an x402 header exchange using:
PAYMENT-REQUIRED
PAYMENT-SIGNATURE
The protocol direction includes standardized v2 concepts such as:
PAYMENT-RESPONSE,- separation of resource descriptions from payment requirements,
- and CAIP-2 network identifiers.
Before any mainnet deployment, the exact request and response schema used by HTTPFacilitator must be verified against the current x402 specification and the chosen facilitator implementation.
Why is this important?
Because a payment protocol is not approximately correct.
The following must match exactly:
- header names,
- typed-data domains,
- field names,
- field encodings,
- network identifiers,
- asset identifiers,
- amount representation,
- signature semantics,
- verification responses,
- and settlement responses.
One incorrect field can produce a request that appears structurally reasonable but cannot be verified or settled.
Protocol conformance is binary:
interoperable or not interoperable
A Go x402 implementation already exists.
Therefore the long-term defensible product is not merely:
HTTP middleware that returns 402
The difficult product is the durable paid-operation kernel.
Consider what happens when the facilitator times out.
Does that mean settlement failed?
No.
It means the outcome is unknown.
That distinction is fundamental.
A timeout may occur after the facilitator accepted the payment but before the server received confirmation. If the server treats "unknown" as "failed" and asks the client to pay again, it may create duplicate charges.
Therefore the system requires an explicit state machine.
For example:
UNPAID
↓
PAYMENT_PRESENT
↓
VERIFIED
↓
SETTLEMENT_PENDING
├─→ SETTLED
├─→ REJECTED
└─→ UNKNOWN
Once settled:
SETTLED
↓
EXECUTING
├─→ COMPLETED
└─→ EXECUTION_FAILED
And once completed:
COMPLETED
↓
REPLAYABLE
A durable implementation must address at least five hard problems.
The payment must authorize the exact request being executed.
The binding should include:
- HTTP method,
- canonical URL,
- normalized route identity,
- request-body hash,
- payment requirements,
- and a nonce or unique operation identifier.
Conceptually:
B = H(method ∥ canonical URL ∥ H(body) ∥ terms ∥ nonce)
Without request binding, a valid payment proof might be replayed against a different payload or endpoint.
A client may retry because:
- the network disconnected,
- the server timed out,
- the facilitator was slow,
- or the client never received the response.
The operation needs an idempotency identity that survives process restarts.
The invariant should be:
one authorized purchase → at most one billable execution
A settlement timeout is not equivalent to a settlement rejection.
The kernel needs reconciliation:
unknown settlement
→ query facilitator
→ recover settled or rejected state
Until reconciliation completes, the request must not be blindly recharged or re-executed.
Suppose payment settled and execution completed, but the connection closed before the client received the artifact.
The client retries.
The correct behavior is not:
charge again and recompute
It is:
recognize completed operation
return stored artifact
The artifact must therefore be durably associated with the payment-bound request identity.
A production system must expose the state transitions that determine money and delivery.
Useful observables include:
- payment challenges issued,
- payment proofs received,
- verification latency,
- verification rejection reasons,
- settlement latency,
- unknown settlement count,
- reconciliation attempts,
- duplicate request count,
- execution duration,
- execution cost,
- realized margin,
- cached replay count,
- and facilitator health.
Without these observables, the operator cannot distinguish:
no demand
from:
broken discovery
or:
invalid payment terms
or:
facilitator outage
or:
worker failures after settlement
The durable state machine, not the initial middleware, is the actual roadmap.
Before mainnet, configure Base Sepolia:
Options.Network = "eip155:84532"and use:
- a Base Sepolia-compatible facilitator,
- testnet USDC or the asset required by that facilitator,
- a test wallet,
- and nonproduction recipient addresses.
Base mainnet is:
eip155:8453
Base Sepolia is:
eip155:84532
One digit changes the economic consequences from simulated to real.
That is not a detail to discover during integration testing.
We can now compress the system into one chain.
A worker defines a bounded reasoning operation:
x → y
A pricer assigns the current price:
P_t
The HTTP kernel publishes payment requirements:
402(P_t)
The client authorizes those terms:
S = Sign(P_t, R)
The facilitator verifies and settles the authorization:
V(S, R) → settled
The worker executes:
y = f(x)
The kernel records cost and revenue:
C_t, P_t
The pricer updates:
P_{t+1} = α · (C_t / (1 − m)) + (1 − α) · P_t
The result is stored and returned:
payment identity → artifact
That is the system.
Not a subscription platform. Not a cryptocurrency storefront. Not a generic model API.
It is a machine-native market for bounded reasoning operations:
discover → request → price → authorize → settle → execute → return → replay safely
One HTTP endpoint sells one well-defined intellectual artifact at a price proportionate to the work required to produce it.
That is precisely the kind of transaction agents can perform without human administration—and precisely the kind of transaction conventional SaaS was never designed to handle.