Y2 Elite workspaces are rolling out for teams
Y2Y2Docs

Pay per Request with x402

Call supported read endpoints without an API key by settling USDC on Base

x402 lets an agent or application pay for a supported Y2 read request without creating an account or API key. Y2 advertises an x402 v2 payment requirement, verifies and settles the signed payment, then serves the normal endpoint response.

Choose bearer auth or x402

ModeUse it for
Bearer API keyRecurring integrations, workspace-scoped data, writes, and plan rate limits
x402Anonymous, one-off, agent-driven access to supported public read operations

A request with Authorization: Bearer ... always takes the API-key path. An invalid bearer token returns its normal 401 or 403; Y2 does not silently fall back to x402. Omit Authorization entirely when you intend to pay per request.

Supported API surfaces

x402 is enabled on registered read operations in these families:

  • Reports, including Markdown, text, signals, graph, audio, and TTS text;
  • News items, recaps, and feed discovery;
  • OSINT feeds and country intelligence;
  • Intel v2 incidents, entities, markets, financial intelligence, signals, cyber, and changes.

It is not an alternative for API-key-only surfaces such as profile management, webhook configuration, or Agent Y2. Check an operation's security and x-x402 fields in the generated endpoint reference before building a payment flow.

Some list routes need explicit public context

Anonymous callers do not have a user or workspace context. For example, GET /reports requires a canonical profileId query parameter on the x402 path.

Read the payment challenge

Send the exact resource request without a bearer key:

curl --include \
  "https://api.y2.dev/api/v1/news?topics=markets&limit=5"

The 402 response includes a base64-encoded PAYMENT-REQUIRED header and the decoded requirement as JSON. Its shape is similar to:

{
  "x402Version": 2,
  "error": "Payment required",
  "resource": {
    "url": "https://api.y2.dev/api/v1/news?topics=markets&limit=5",
    "description": "Real-time direct-source news terminal items",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "2000",
      "payTo": "0x...",
      "maxTimeoutSeconds": 60,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ],
  "extensions": {
    "bazaar": { "discoverable": true }
  }
}

Do not hard-code asset, payTo, EIP-712 domain fields, or the amount from this example. Read and validate the returned requirement every time. amount is expressed in atomic token units; USDC uses six decimals, so "2000" represents $0.002.

Production requirements use Base mainnet (eip155:8453). Development deployments can use Base Sepolia (eip155:84532). The network is a CAIP-2 identifier, not the legacy base slug.

Make a paid request in TypeScript

The following flow matches the x402 packages used by the current Y2 implementation:

npm install @x402/core@^2.18.0 @x402/evm@^2.18.0 viem@^2.55.2

Create the signer in a server-side runtime or secure wallet environment. Never expose a raw private key in browser code.

import { x402Client } from "@x402/core/client";
import { x402HTTPClient } from "@x402/core/http";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const privateKey = process.env.X402_PRIVATE_KEY as `0x${string}` | undefined;
if (!privateKey) throw new Error("X402_PRIVATE_KEY is required");

const signer = privateKeyToAccount(privateKey);
const core = new x402Client().register("eip155:*", new ExactEvmScheme(signer));
const x402 = new x402HTTPClient(core);

const url = "https://api.y2.dev/api/v1/news?topics=markets&limit=5";
const challengeResponse = await fetch(url, { headers: { Accept: "application/json" } });

if (challengeResponse.status !== 402) {
  throw new Error(`Expected an x402 challenge, received ${challengeResponse.status}`);
}

const challengeBody = await challengeResponse.json();
const requirement = x402.getPaymentRequiredResponse(
  (name) => challengeResponse.headers.get(name),
  challengeBody,
);

const option = requirement.accepts[0];
if (!option || option.scheme !== "exact" || option.network !== "eip155:8453") {
  throw new Error("Y2 returned an unsupported payment option");
}

const maxAtomicUsdc = 2_000n;
if (BigInt(option.amount) > maxAtomicUsdc) {
  throw new Error("Payment exceeds the client price ceiling");
}

const payment = await x402.createPaymentPayload(requirement);
const paidResponse = await fetch(url, {
  headers: {
    Accept: "application/json",
    ...x402.encodePaymentSignatureHeader(payment),
  },
});

const settlement = paidResponse.headers.has("PAYMENT-RESPONSE")
  ? x402.getPaymentSettleResponse((name) => paidResponse.headers.get(name))
  : null;
const result = await paidResponse.json();

console.log({ status: paidResponse.status, settlement, result });

The price ceiling above is specific to the $0.002 News example. Set a ceiling appropriate to the operation you selected. Keep the first and second request URL, method, query, and body identical.

Understand the headers

HeaderDirectionMeaning
PAYMENT-REQUIREDResponseBase64-encoded x402 v2 challenge
PAYMENT-SIGNATURERequestBase64-encoded signed payment payload
PAYMENT-RESPONSEResponseBase64-encoded settlement result
AuthorizationRequestSelects bearer authentication when present

X-PAYMENT and X-PAYMENT-RESPONSE are legacy x402 v1 names. New Y2 clients should use the v2 headers above.

Prices and wallet limits

Each operation maps to one current tier. The generated endpoint page is the source of truth for the operation's exact price.

TierPricePer wallet/minutePer wallet/day
Health/meta$0.0016010,000
Standard read$0.002605,000
Enriched data$0.01302,000
Premium report list$0.0510500
Premium single report$0.2510200
Premium report audio$0.505100

Y2 also applies a global per-endpoint circuit breaker. A wallet limit returns 429; an endpoint capacity limit returns 503. Both are checked before settlement, so the rejected request is not charged.

Store and inspect a receipt

The EIP-3009 authorization inside the signed payment contains a nonce. Treat that nonce as a receipt lookup capability and store it with the request result:

curl "https://api.y2.dev/api/v1/x402/receipts/$PAYMENT_NONCE"

The lookup is public to anyone who knows the nonce. It returns the payer address, endpoint, USD amount, network, status, and—when available—the transaction hash and settlement time. It does not return the signature, token authorization, pay-to address, or full payment payload.

Receipt statusMeaning
verify_failedThe facilitator rejected the payment
rate_limitedWallet or endpoint limits blocked the request before settlement
replay_blockedThe payer and nonce combination was already recorded
settle_failedVerification passed but settlement did not complete
settledPayment settled and Y2 invoked the resource handler
handler_failedPayment settled, then the resource handler threw

Settlement happens before resource execution

A settled payment can still be followed by an application response such as 400, 404, or a temporary data-readiness error. Validate resource IDs and parameters before signing, inspect the paid response status and body, and retain the nonce and PAYMENT-RESPONSE metadata for support.

Handle failures

StatusTypical cause
401 or 403Invalid bearer key or missing bearer scope; no x402 fallback
402Missing or invalid payment, unsupported payment payload, or nonce replay
429Per-wallet minute or daily limit exceeded
503x402 unavailable, settlement infrastructure unavailable, or endpoint circuit breaker open
Other endpoint statusPayment settled, then the normal resource handler returned its own result

Never reuse an authorization nonce. When a result is ambiguous, check the receipt before creating a new payment so you do not confuse a settled request with a transport failure.