Examples

These examples show the “challenge → sign → retry” pattern. For a deeper explanation, see Payment Flow (x402).

cURL (see the headers)

curl -i "https://sentiment-api.kytona.com/v2/snapshot/crypto?format=compact_trading&fields=ts,mood,rec"

TypeScript (v2, Base/EVM)

import { decodePaymentRequiredHeader } from "@x402/core/http";
import { ExactEvmScheme } from "@x402/evm";

export async function fetchPaid<T>(url: string) {
  const challenge = await fetch(url);
  if (challenge.status !== 402) throw new Error(`Expected 402, got ${challenge.status}`);

  let requirements: any = null;
  try {
    requirements = await challenge.json();
  } catch {}
  if (!requirements?.accepts?.length) {
    const header = challenge.headers.get("PAYMENT-REQUIRED");
    if (!header) throw new Error("Missing PAYMENT-REQUIRED header");
    requirements = decodePaymentRequiredHeader(header);
  }

  const scheme = new ExactEvmScheme({
    privateKey: process.env.EVM_PRIVATE_KEY!,
    network: "eip155:8453",
  });
  const sig = await scheme.sign(requirements);

  const paid = await fetch(url, { headers: { "PAYMENT-SIGNATURE": sig.encodedSignature } });
  if (!paid.ok) throw new Error(`Paid request failed: ${paid.status} ${await paid.text()}`);
  return (await paid.json()) as T;
}

const url =
  "https://sentiment-api.kytona.com/v2/snapshot/crypto?format=compact_trading&fields=ts,mood,rec";
const data = await fetchPaid<{ mood: number; rec: string }>(url);
console.log(data);

Python (conceptual)

The exact import paths depend on the Python x402 client you’re using. The core pattern is identical:

  1. GET the endpoint

  2. On 402, parse requirements

  3. Sign locally

  4. Retry with PAYMENT-SIGNATURE

Last updated