Getting Started
Buyer/Client Guide
Send x402 payments to sellers with a TypeScript client.
Send payments to sellers.
Install
npm install @x402/core @x402/evm viem dotenvCode
import "dotenv/config";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import type { Network, PaymentRequired } from "@x402/core/types";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const endpoint = "https://api.naven.network/x402-test/ping";
const network = "eip155:4663" satisfies Network;
function normalizePrivateKey(privateKey: string): `0x${string}` {
return privateKey.startsWith("0x")
? (privateKey as `0x${string}`)
: `0x${privateKey}`;
}
function assertPaymentRequired(value: unknown): asserts value is PaymentRequired {
if (
!value ||
typeof value !== "object" ||
!("x402Version" in value) ||
!("accepts" in value) ||
!Array.isArray(value.accepts)
) {
throw new Error("Response did not contain a valid x402 payment challenge");
}
}
async function main() {
const privateKey = process.env.X402_PRIVATE_KEY;
if (!privateKey) {
throw new Error("Set X402_PRIVATE_KEY before running");
}
const account = privateKeyToAccount(normalizePrivateKey(privateKey));
const client = new x402Client();
registerExactEvmScheme(client, {
signer: account,
networks: [network],
});
const httpClient = new x402HTTPClient(client);
const challengeResponse = await fetch(endpoint);
const challenge = await challengeResponse.json();
if (challengeResponse.status !== 402) {
throw new Error(`Expected 402 challenge, got ${challengeResponse.status}`);
}
assertPaymentRequired(challenge);
const paymentPayload = await httpClient.createPaymentPayload(challenge);
const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);
const paidResponse = await fetch(endpoint, {
headers: {
...paymentHeaders,
"Access-Control-Expose-Headers": "PAYMENT-RESPONSE, X-PAYMENT-RESPONSE",
},
});
const body = await paidResponse.json();
const paymentResult = httpClient.parsePaymentResult({
status: paidResponse.status,
getHeader: name => paidResponse.headers.get(name),
body,
});
console.log({
status: paidResponse.status,
paymentStatus: paymentResult.paymentStatus,
paymentHeader: paymentResult.header,
body,
});
}
main().catch(error => {
console.error(error);
process.exit(1);
});