Getting Started
Seller/Server Guide
Accept x402 payments in a Hono server.
Start accepting 402 payments in your server in 2 minutes.
Install
npm install @x402/core dotenv honoCode
import "dotenv/config";
import { Hono } from "hono";
import {
decodePaymentSignatureHeader,
encodePaymentRequiredHeader,
encodePaymentResponseHeader,
} from "@x402/core/http";
import { HTTPFacilitatorClient } from "@x402/core/server";
import type {
Network,
PaymentPayload,
PaymentRequired,
PaymentRequirements,
} from "@x402/core/types";
const facilitator = new HTTPFacilitatorClient({
url: "https://facilitator.naven.network",
});
const network = "eip155:4663" satisfies Network;
const asset = "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168";
const payTo = process.env.X402_PAY_TO as `0x${string}`;
const app = new Hono();
function toAtomicAmount(value: string, decimals: number) {
const [whole = "0", fraction = ""] = value.replace("$", "").split(".");
const paddedFraction = `${fraction}${"0".repeat(decimals)}`.slice(0, decimals);
return BigInt(`${whole}${paddedFraction}`).toString();
}
function getPaymentRequired(resourceUrl: string): PaymentRequired {
const requirement: PaymentRequirements = {
scheme: "exact",
network,
asset,
amount: toAtomicAmount("$0.0001", 6),
payTo,
maxTimeoutSeconds: 300,
extra: {
name: "Global Dollar",
version: "1",
},
};
return {
x402Version: 2,
resource: {
url: resourceUrl,
description: "Paid weather API",
mimeType: "application/json",
serviceName: "Weather API",
},
accepts: [requirement],
};
}
function getPaymentHeader(headers: Headers) {
return headers.get("payment-signature") ?? headers.get("x-payment");
}
app.get("/weather", async c => {
const paymentRequired = getPaymentRequired(c.req.url);
const paymentHeader = getPaymentHeader(c.req.raw.headers);
if (!paymentHeader) {
c.header("PAYMENT-REQUIRED", encodePaymentRequiredHeader(paymentRequired));
c.header("Access-Control-Expose-Headers", "PAYMENT-REQUIRED");
return c.json(paymentRequired, 402);
}
const paymentPayload = decodePaymentSignatureHeader(
paymentHeader,
) as PaymentPayload;
const paymentRequirements = paymentRequired.accepts[0];
const verifyResult = await facilitator.verify(
paymentPayload,
paymentRequirements,
);
if (!verifyResult.isValid) {
return c.json(
{ ...paymentRequired, error: verifyResult.invalidReason },
402,
);
}
const settleResult = await facilitator.settle(
paymentPayload,
paymentRequirements,
);
const paymentResponse = encodePaymentResponseHeader(settleResult);
c.header("PAYMENT-RESPONSE", paymentResponse);
c.header("X-PAYMENT-RESPONSE", paymentResponse);
c.header(
"Access-Control-Expose-Headers",
"PAYMENT-RESPONSE, X-PAYMENT-RESPONSE",
);
if (!settleResult.success) {
return c.json(settleResult, 402);
}
return c.json({
report: {
weather: "sunny",
temperature: 70,
},
});
});
Bun.serve({
fetch: app.fetch,
port: 4021,
});