Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs-test.rye.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

← x402

This walkthrough shows how to purchase a product through Rye’s x402 endpoint using the AgentCash client. AgentCash handles the 402 → sign → retry loop transparently, so your code reads like a normal HTTP call.

Prerequisites

  • An AgentCash wallet with a small USDC balance on Base (≥ $1 is plenty for testing — covers the access fees and a low-priced test purchase)
  • A product URL from a supported merchant (Shopify, Amazon, etc.)
  • The AgentCash CLI or SDK — follow the AgentCash setup guide to install and initialize a wallet
The first time you initialize AgentCash it generates a wallet and stores keys at ~/.agentcash/wallet.json (EVM) and ~/.agentcash/solana-wallet.json (Solana). Top up the wallet with USDC on the network you plan to use before making any paid call.

End-to-end purchase

The example below uses AgentCash’s wallet.fetch, which is a fetch-compatible function that automatically signs and retries 402 responses.
const baseUrl = "https://x402.rye.com";

// 1. Create a checkout intent — pays $0.02 over x402 automatically.
const created = await wallet.fetch(`${baseUrl}/v1/checkout-intents`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    productUrl: "https://shop.example.com/running-shoes",
    quantity: 1,
    buyer: {
      firstName: "Jane",
      lastName: "Doe",
      email: "jane@example.com",
      phone: "+14155551234",
      address1: "123 Market St",
      city: "San Francisco",
      province: "CA",
      country: "US",
      postalCode: "94103",
    },
  }),
}).then((r) => r.json());

const intentId = created.id;

// 2. Poll for the offer — free, no signature required.
async function pollUntil(targetState: string) {
  while (true) {
    const r = await fetch(`${baseUrl}/v1/checkout-intents/${intentId}`, {
      headers: { "X-Wallet-Address": wallet.address },
    });
    const intent = await r.json();
    if (intent.state === targetState || intent.state === "failed") return intent;
    await new Promise((res) => setTimeout(res, 3000));
  }
}

const ready = await pollUntil("awaiting_confirmation");
if (ready.state === "failed") throw new Error(ready.failureReason?.message);

// 3. Inspect the offer and decide whether to proceed.
const totalSubunits = ready.offer.cost.total.amountSubunits;
const budgetSubunits = 15000; // $150.00
if (totalSubunits > budgetSubunits) throw new Error("over budget");

// 4. Confirm — pays purchase total + $0.03 over x402 in a single signed transfer.
await wallet.fetch(`${baseUrl}/v1/checkout-intents/${intentId}/confirm`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    paymentMethod: { type: "x402", network: "base" },
  }),
});

// 5. Poll for completion.
const final = await pollUntil("completed");
console.log("order placed:", final.orderId);

What happens behind the scenes

  • wallet.fetch receives a 402 Payment Required from the proxy with a PAYMENT-REQUIRED header. It signs an EIP-3009 USDC transfer for the requested amount and retries the same request with a PAYMENT-SIGNATURE header.
  • For step 1 the signed transfer is for 0.02.Forstep4itcoverstheofferspurchasetotalplusthe0.02. For step 4 it covers the offer's purchase total plus the 0.03 API fee — bundled into a single signed transfer.
  • GET calls in steps 2 and 5 are free and use a normal fetch. The X-Wallet-Address header scopes the read to the wallet that paid for the intent.
  • After step 4 returns, Rye places the order asynchronously. The intent moves to placing_order, then to completed or failed. See Checkout Intent Lifecycle for the full state machine.

Timing

StepTypical latency
Create intent (incl. on-chain finality)1–3 s
Offer retrieval5–20 s
Confirm< 1 s after signature
Order placement30 s – several min
Order placement runs asynchronously — your code does not block while Rye places the order at the merchant. Keep polling GET /v1/checkout-intents/:id until you see state: "completed" or state: "failed".

Failure modes

  • Insufficient wallet balance — the on-chain transfer fails; the intent moves to failed and no order is placed.
  • Offer retrieval fails (out of stock, unsupported product) — state: "failed" after step 2; the $0.02 access fee is not refunded because the offer retrieval work was performed.
  • Order placement fails at the merchant — state: "failed" after step 4; the purchase amount is automatically refunded to the signing wallet on-chain.
  • Signature expired between calls — the retry returns 400 with a fresh PAYMENT-REQUIRED; wallet.fetch re-signs and retries automatically.
See the Endpoint Reference for full request and response shapes, including how to call the API without the AgentCash SDK.