HTTP 402 · Payment Required402
The internet has had a payment status code since 1997.
Nobody used it until agents needed to
scheme: upi
network: upi:in
settled via Razorpay
PAYMENT-REQUIRED
{
"x402Version": 2,
"accepts": [
{
"scheme": "upi",
"network": "upi:in",
"amount": "100",
"asset": "INR",
"payTo": "merchant@upi",
"maxTimeoutSeconds": 180
}
]
}scroll
the old way
01Manual
KYC verification
Identity checks before an agent can transact.
02Manual
API key provisioning
Manual credential exchange, per integration.
03Manual
Recurring subscriptions
Standing authorization instead of per-request consent.
raw protocol → rupee-settled payment
The Bridge
One HTTP 402 response. One scan. The agent never leaves the request.
PAYMENT-REQUIRED → UPI
PAYMENT-REQUIRED
{
"x402Version": 2,
"accepts": [{
"scheme": "upi",
"network": "upi:in",
"amount": "10000",
"asset": "INR",
"payTo": "merchant@upi",
"maxTimeoutSeconds": 180
}]
}₹100.00
merchant@upiupi://pay?pa=merchant@upi&pn=fiat402%20Demo%20Merchant&am=100.00&cu=INRUPI IntentTravelBotflagged for review
Confirm
Declined
live proof
The real control tower, replayed
Agent console
Replays a captured run -- no live request is sent from this page.
Idle -- run a persona above to see it live.
State machine
created → pending → approved|declined|expired → settled|failed
No requests yet. The rail lights up as soon as one enters "pending".
Created
created
Payment Link
pending
Payer outcome
approved
declined
expired
Terminal
settled
failed
Decision
No request in flight
Not available on the live event stream -- the deterministic/AI decision is returned in the facilitator's /verify response, not published to fiat402:events.
Raw x402 traffic
No request observed yet
No PAYMENT-REQUIRED / PAYMENT-SIGNATURE / PAYMENT-RESPONSE headers observed on the live feed. This panel decodes those HTTP headers; the dashboard's live feed is the Redis event channel, which doesn't carry them.
the actual protocol
Two lines, either side
For merchants
import { withX402Payment } from "../../../lib/x402-middleware";
export async function GET(request: Request): Promise<Response> {
return withX402Payment(request, RESOURCE, () =>
Response.json({
data: "premium market data",
generatedAt: new Date().toISOString(),
}),
);
}For agents
// x402-upi-client/src/index.ts
export function registerUpiScheme(client: x402Client, options?: UpiSchemeClientOptions): x402Client {
return client.register("upi:in", new UpiSchemeClient(options));
}
// real usage (x402-upi-client/test/demo.ts):
const client = new x402Client();
client.setSpendControls({ allowedAssets: true });
registerUpiScheme(client, {
payerVpa: process.env.DEMO_PAYER_VPA,
agentMetadata: { taskContext },
});fiat402