> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relaycore.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# x402 Payment Protocol

> HTTP 402 payment flow with EIP-3009 authorization and gasless Facilitator settlement

## Overview

The x402 protocol is RelayCore's implementation of HTTP 402 Payment Required, enabling **gasless payments** where agents pay for services without submitting blockchain transactions. Instead, agents sign EIP-3009 authorizations off-chain, and the Crypto.com Facilitator SDK settles payments on Cronos.

**Key Benefits**:

* **Gasless**: Agents never pay gas fees
* **Instant**: No waiting for block confirmations
* **Secure**: EIP-3009 standard with signature verification
* **Scalable**: Session-based budgets enable micro-payments

## Complete Payment Flow

<Steps>
  <Step title="1. Agent Requests Protected Resource">
    Agent calls a protected API endpoint without payment:

    ```bash theme={null}
    POST /api/perpai/quote HTTP/1.1
    Host: api.relaycore.xyz
    Content-Type: application/json

    {
      "pair": "BTC-USD",
      "side": "long",
      "leverage": 10,
      "sizeUsd": 1000
    }
    ```
  </Step>

  <Step title="2. Server Returns 402 Payment Required">
    The `requirePayment` middleware intercepts the request and returns 402:

    ```json theme={null}
    HTTP/1.1 402 Payment Required
    {
      "error": "Payment Required",
      "paymentId": "pay_abc123",
      "paymentRequirements": {
        "scheme": "exact",
        "network": "cronos-testnet",
        "payTo": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
        "asset": "0xc01efAaF7C5C61bEbFAeb358E1161b537b8bC0e0",
        "maxAmountRequired": "10000",
        "maxTimeoutSeconds": 300,
        "resource": "/api/perpai/quote",
        "description": "PerpAI quote aggregation"
      },
      "message": "Payment of 10000 base units required",
      "network": "cronos-testnet"
    }
    ```

    **Payment Requirements Breakdown**:

    * `payTo`: Merchant wallet address (service provider)
    * `asset`: USDC contract address on Cronos Testnet
    * `maxAmountRequired`: Amount in base units (10000 = 0.01 USDC with 6 decimals)
    * `resource`: The protected endpoint URL
  </Step>

  <Step title="3. Agent Generates EIP-3009 Authorization">
    Agent uses the Facilitator SDK to generate a signed payment header:

    ```typescript theme={null}
    import { Facilitator, CronosNetwork } from '@crypto.com/facilitator-client';
    import { ethers } from 'ethers';

    const facilitator = new Facilitator({ 
      network: CronosNetwork.CronosTestnet 
    });

    const wallet = new ethers.Wallet(privateKey, provider);

    // Generate payment header with signature
    const paymentHeader = await facilitator.generatePaymentHeader({
      to: paymentRequirements.payTo,
      value: paymentRequirements.maxAmountRequired,
      asset: paymentRequirements.asset,
      signer: wallet,
      validAfter: Math.floor(Date.now() / 1000) - 60,
      validBefore: Math.floor(Date.now() / 1000) + 300
    });
    ```

    **What's in the Payment Header**:

    * EIP-3009 `TransferWithAuthorization` parameters
    * EIP-712 signature proving authorization
    * Nonce from USDC contract (prevents replay)
    * Validity window (5 minutes)
  </Step>

  <Step title="4. Agent Submits Payment for Settlement">
    Agent sends the signed authorization to the settlement endpoint:

    ```bash theme={null}
    POST /api/pay HTTP/1.1
    Content-Type: application/json

    {
      "paymentId": "pay_abc123",
      "paymentHeader": "0x...",
      "paymentRequirements": {
        "scheme": "exact",
        "network": "cronos-testnet",
        "payTo": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
        "asset": "0xc01efAaF7C5C61bEbFAeb358E1161b537b8bC0e0",
        "maxAmountRequired": "10000",
        "maxTimeoutSeconds": 300,
        "resource": "/api/perpai/quote"
      }
    }
    ```
  </Step>

  <Step title="5. Facilitator Verifies and Settles On-Chain">
    Server uses Facilitator SDK to verify signature and execute transfer:

    ```typescript theme={null}
    // From: src/services/x402/facilitator-service.ts
    const verifyRequest = facilitator.buildVerifyRequest(
      paymentHeader,
      paymentRequirements
    );

    // Verify EIP-3009 signature
    const verifyResult = await facilitator.verifyPayment(verifyRequest);
    if (!verifyResult.isValid) {
      throw new Error('Invalid signature');
    }

    // Settle payment on-chain (Facilitator pays gas)
    const settleResult = await facilitator.settlePayment(verifyRequest);
    // Returns: { txHash: '0x...', success: true }
    ```

    **Gasless Magic**: The Facilitator executes `transferWithAuthorization` on the USDC contract, paying gas fees while transferring USDC from agent to merchant.
  </Step>

  <Step title="6. Server Records Payment and Grants Entitlement">
    Payment is recorded in database and cached in memory:

    ```typescript theme={null}
    // Store in Supabase
    await supabase.from('payments').insert({
      payment_id: paymentId,
      tx_hash: settleResult.txHash,
      from_address: userAddress,
      to_address: paymentRequirements.payTo,
      amount: paymentRequirements.maxAmountRequired,
      resource_url: paymentRequirements.resource,
      status: 'settled'
    });

    // Cache entitlement for fast lookups
    entitlementCache.set(paymentId, {
      paymentId,
      resourceUrl: paymentRequirements.resource,
      userAddress,
      timestamp: Date.now()
    });
    ```

    Server responds with success:

    ```json theme={null}
    HTTP/1.1 200 OK
    {
      "success": true,
      "paymentId": "pay_abc123",
      "txHash": "0x1234...abcd",
      "timestamp": 1706000000000
    }
    ```
  </Step>

  <Step title="7. Agent Retries Request with Payment ID">
    Agent retries the original request with the payment ID header:

    ```bash theme={null}
    POST /api/perpai/quote HTTP/1.1
    X-Payment-Id: pay_abc123
    Content-Type: application/json

    {
      "pair": "BTC-USD",
      "side": "long",
      "leverage": 10,
      "sizeUsd": 1000
    }
    ```
  </Step>

  <Step title="8. Server Verifies Entitlement and Returns Content">
    Middleware checks entitlement cache and database:

    ```typescript theme={null}
    // Check cache first (fast path)
    if (entitlementCache.has(paymentId)) {
      const entitlement = entitlementCache.get(paymentId);
      if (entitlement.resourceUrl === resourceUrl) {
        req.isEntitled = true;
        return next(); // Grant access
      }
    }

    // Check database (fallback)
    const { data } = await supabase
      .from('payments')
      .select('*')
      .eq('payment_id', paymentId)
      .eq('resource_url', resourceUrl)
      .eq('status', 'settled')
      .single();

    if (data) {
      req.isEntitled = true;
      return next();
    }
    ```

    Server returns the protected content:

    ```json theme={null}
    HTTP/1.1 200 OK
    {
      "quote": {
        "pair": "BTC-USD",
        "entryPrice": 42500.50,
        "liquidationPrice": 38250.45,
        "fundingRate": 0.0001,
        "bestVenue": "VVS Finance"
      }
    }
    ```
  </Step>
</Steps>

## Session-Based Payments

For agents making multiple requests, **session escrow** eliminates repeated x402 flows:

<Steps>
  <Step title="1. Create Session with Budget">
    ```bash theme={null}
    POST /api/sessions/create
    {
      "maxSpend": "100.00",
      "duration": 86400
    }
    ```

    Returns 402 for session deposit.
  </Step>

  <Step title="2. Pay Session Deposit via x402">
    Agent pays once to fund the session budget.
  </Step>

  <Step title="3. Use Session for All Requests">
    ```bash theme={null}
    POST /api/perpai/quote
    X-Session-Id: session_xyz789

    # Payment automatically deducted from session budget
    # No 402, no signing, instant execution
    ```

    **Budget Tracking**:

    ```typescript theme={null}
    const remaining = session.deposited - session.released;
    if (remaining >= amountRequired) {
      session.released += amountRequired;
      // Execute service
    }
    ```
  </Step>
</Steps>

**Session Benefits**:

* One payment, unlimited requests (within budget)
* Real-time balance tracking
* Automatic refunds on expiration
* Perfect for autonomous agents

## Implementation Guide

### Protecting Routes with x402

```typescript theme={null}
// src/api/perpai-routes.ts
import { requirePayment } from '@/services/x402/payment-middleware';

router.post('/quote',
  requirePayment({
    merchantAddress: process.env.PAYMENT_RECIPIENT_ADDRESS!,
    amount: '10000', // 0.01 USDC
    resourceUrl: '/api/perpai/quote',
  }),
  async (req, res) => {
    // This code only runs if payment is verified
    const quote = await perpaiService.getQuote(req.body);
    res.json(quote);
  }
);
```

### Payment Settlement Endpoint

```typescript theme={null}
// src/api/payment-routes.ts
import { handlePaymentSettlement } from '@/services/x402/payment-middleware';

router.post('/pay', handlePaymentSettlement);
```

The `handlePaymentSettlement` function:

1. Validates payment parameters
2. Builds Facilitator verify request
3. Verifies EIP-3009 signature
4. Settles payment on-chain
5. Records in database
6. Caches entitlement
7. Returns transaction hash

### Entitlement Caching

```typescript theme={null}
// In-memory cache for fast lookups
const entitlementCache = new Map<string, {
  paymentId: string;
  resourceUrl: string;
  userAddress: string;
  timestamp: number;
}>();

// Cache expires after 24 hours
setInterval(() => clearExpiredEntitlements(24 * 60 * 60 * 1000), 60 * 60 * 1000);
```

## Security Guarantees

<AccordionGroup>
  <Accordion title="EIP-3009 Signature Verification">
    Every payment header contains an EIP-712 signature that proves:

    * The payer authorized the exact amount
    * The payer authorized the exact recipient
    * The authorization is time-bound
    * The nonce is unique (prevents replay)

    The Facilitator SDK verifies all parameters before settlement.
  </Accordion>

  <Accordion title="Nonce Tracking">
    USDC contract maintains a nonce counter for each address. Each `TransferWithAuthorization` must use the next sequential nonce. This prevents:

    * Replay attacks
    * Double-spending
    * Authorization reuse
  </Accordion>

  <Accordion title="Time-Bound Authorizations">
    Every authorization includes:

    * `validAfter`: Earliest timestamp for execution
    * `validBefore`: Latest timestamp for execution

    Expired authorizations are rejected by the USDC contract.
  </Accordion>

  <Accordion title="Amount Enforcement">
    The `maxAmountRequired` field enforces the exact payment amount. The Facilitator rejects any attempt to:

    * Overpay
    * Underpay
    * Change the amount after signing
  </Accordion>

  <Accordion title="Resource Binding">
    Each payment is bound to a specific `resource` URL. Entitlements are only valid for the exact resource that was paid for.
  </Accordion>
</AccordionGroup>

## Network Configuration

| Network        | Chain ID | USDC Contract                                | Facilitator                |
| -------------- | -------- | -------------------------------------------- | -------------------------- |
| Cronos Testnet | 338      | `0xc01efAaF7C5C61bEbFAeb358E1161b537b8bC0e0` | Crypto.com Facilitator SDK |
| Cronos Mainnet | 25       | `0xc21223249CA28397B4B6541dfFaEcC539BfF0c59` | Crypto.com Facilitator SDK |

## Environment Variables

```bash theme={null}
# Required for x402 settlement
WALLET_PRIVATE_KEY=0x...           # Server wallet for receiving payments
PAYMENT_RECIPIENT_ADDRESS=0x...    # Merchant address
USDC_TOKEN_ADDRESS=0xc01efAaF...   # USDC contract on Cronos Testnet
VITE_CRONOS_NETWORK=cronos-testnet # Network selection
```

## Indexer Integration

The **Payment Indexer** runs every 5 minutes to:

1. Query Cronos Explorer API for recent USDC transfers
2. Match `tx_hash` to `payments` table records
3. Update `block_number` and `status` fields
4. Trigger reputation updates for services

```typescript theme={null}
// src/services/indexer/payment-indexer.ts
export async function indexPayments() {
  const recentPayments = await supabase
    .from('payments')
    .select('*')
    .is('block_number', null)
    .order('timestamp', { ascending: false })
    .limit(100);

  for (const payment of recentPayments.data) {
    const tx = await cronosExplorer.getTransaction(payment.tx_hash);
    if (tx.blockNumber) {
      await supabase
        .from('payments')
        .update({ block_number: tx.blockNumber })
        .eq('payment_id', payment.payment_id);
    }
  }
}
```

## Error Handling

| Error                       | Cause                          | Resolution                    |
| --------------------------- | ------------------------------ | ----------------------------- |
| `Insufficient USDC balance` | Agent wallet lacks USDC        | Fund wallet with USDC         |
| `Invalid signature`         | Signature verification failed  | Regenerate payment header     |
| `Nonce already used`        | Replay attack or stale nonce   | Get fresh nonce from contract |
| `Authorization expired`     | `validBefore` timestamp passed | Generate new authorization    |
| `Payment already settled`   | Duplicate payment ID           | Use new payment ID            |

## Next Steps

<CardGroup cols={2}>
  <Card title="Session Escrow" icon="wallet" href="/essentials/sessions">
    Learn about gasless session budgets
  </Card>

  <Card title="SDK Integration" icon="code" href="/sdk/agent-sdk">
    Integrate x402 in your agent
  </Card>

  <Card title="MCP Tools" icon="robot" href="/mcp/tools-reference">
    Use x402 via MCP server
  </Card>

  <Card title="First Payment Guide" icon="rocket" href="/guides/first-payment">
    Complete tutorial with code
  </Card>
</CardGroup>
