x402

x402 is Shotoku’s first payment rail. The same authorization model works for any rail.

What is x402?

x402 is an open payment protocol from Coinbase that lets a client pay for a resource over plain HTTP — no account, no API key, no login. It revives the long-dormant HTTP 402 Payment Required status code and turns it into a pay-per-request handshake, settled in stablecoins (typically USDC).

That makes it a natural fit for agents: a machine can pay for exactly what it uses, per request, with nothing but a wallet that can sign. No custody, no billing relationship.

The 402 handshake

A single paid request takes two round-trips:

1. Agent requests a resource GET /premium-data 2. Server answers 402 + requirements: pay 0.05 USDC to 0xABC… on Base 3. Agent signs a payment GET /premium-data + X-PAYMENT header 4. Server verifies + settles on-chain, returns the resource
  • Step 2 carries the payment requirements: how much, which token, which network, and the recipient address.
  • Step 3 carries the payment payload: a signed authorization to transfer the stablecoin. A facilitator verifies it and settles on-chain.

No password is ever exchanged. The agent proves it can pay by signing, not by logging in.


Where Shotoku fits

Shotoku inserts itself between step 2 and step 3 — after the agent learns the price, before it signs anything.

2. Server → 402: "pay 0.05 USDC to 0xABC…" │ ↓ ★ Shotoku.authorize() ← the decision point │ approved → continue to step 3 (sign + pay) denied / pending → stop, surface to a human │ ↓ 3. Agent signs and pays

This is the only moment where both of these are true at once:

  • The agent knows the full cost — amount, recipient, and resource were just delivered in the 402.
  • Nothing irreversible has happened yet — no signature, no settlement.

Before step 2 there is no amount to evaluate. After step 3 the money is already gone. That narrow gap is the only place an authorization layer can do its job.


Mapping the 402 to an authorization request

The 402 response hands Shotoku exactly the fields authorize() needs:

From the 402 handshakeAuthorizeRequest field
The agent making the requestactor
It is a paymentaction: "purchase"
The recipient / endpoint paidresource
The amount required (0.05 USDC)amount
The protocolrail: "x402"

One detail matters: x402 amounts are usually sent in atomic units. For USDC, 50000 atomic units means 0.05 USDC because USDC uses 6 decimals. Shotoku normalizes that into a regular decimal before policy evaluation, then records the original payment details in context for audit.


Integration

On receiving a 402 response, before signing the payment:

x402-intercept.ts
import { authorize } from "@shotoku/core";

// Called after the 402 response arrives, before signing
async function handlePaymentRequired(
  paymentRequirements: PaymentRequirements,
  agentId: string,
) {
  const decision = await authorize(
    {
      actor:    agentId,
      action:   "purchase",
      resource: paymentRequirements.recipient,
      rail:     "x402",
      amount:   paymentRequirements.maxAmountRequired / 1_000_000, // USDC 6 decimals
      context:  { network: paymentRequirements.network, raw: paymentRequirements },
    },
    { policyPath: "./policy.yaml", ledgerPath: "./data/decisions.jsonl" },
  );

  if (decision.approved) {
    // proceed to step 3: sign and send the X-PAYMENT request
    return signPayment(paymentRequirements);
  }

  // stop — decision is recorded, waiting for a human if pending
  throw new Error(`Payment blocked: ${decision.status} [${decision.decisionId}]`);
}

What Shotoku does not do

Shotoku is an authorization layer, not a wallet. It never holds funds, never stores private keys, never signs or settles a payment. The agent’s own wallet signs. The facilitator settles on-chain. Shotoku answers one question — should this payment be allowed? — and records the answer locally.


Status

The current implementation in this repo includes:

  • core/src/x402.ts — the interception and authorization flow
  • examples/x402-demo.ts — an end-to-end demo
  • examples/policy-x402.yaml — a sample policy for x402 spending

The demo does not sign or settle a payment. It shows the safe point where Shotoku authorizes before signing would happen.

The same authorization pattern extends to any payment or action rail. x402 is the first integration, not the only one. See the policy reference →