NavenDocs
NavenDocs
Introduction
QuickstartHow x402 Payments WorkBuyer/Client GuideSeller/Server Guide
Back to Naven Network
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 hono

Code

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,
});

Buyer/Client Guide

Send x402 payments to sellers with a TypeScript client.

Marketplace

Request crypto market and token-risk data with a wallet payment for each request.

On this page

InstallCode