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

# x402 (USDC)

> Pay per request in USDC on Solana or Base via the x402 protocol.

[x402](https://x402.org) is an open protocol that maps the long-dormant HTTP `402 Payment Required` status code onto modern stablecoin rails. Syntalic implements x402 on both **Solana** and **Base** for USDC.

The Syntalic server is also indexed on **[x402scan](https://www.x402scan.com/server/fdf15e0c-8d66-49ae-acbb-d872c75e5147)** so any x402-aware agent can discover it without prior knowledge of the URL.

## How it works

```mermaid theme={null}
sequenceDiagram
    participant Agent
    participant API as Syntalic API
    participant Chain as Solana / Base

    Agent->>API: GET /v1/shopper/best-price?q=...
    API-->>Agent: 402 Payment Required<br/>{ recipient, price, chain }
    Agent->>Agent: Sign USDC transfer authorization
    Agent->>API: GET /v1/shopper/best-price?q=...<br/>X-Payment: <signed-auth>
    API->>Chain: Submit transfer
    Chain-->>API: Confirmed
    API-->>Agent: 200 OK<br/>{ best, alternatives, ... }
```

The payment authorization is bound to the specific request — it cannot be replayed against a different endpoint.

## Integrate with `@x402/fetch`

The official `@x402/fetch` wrapper handles the full handshake — discovery, signing, retry — transparently:

<CodeGroup>
  ```ts Solana theme={null}
  import { wrapFetchWithPayment } from "@x402/fetch";
  import { createSolanaSigner } from "@x402/svm";

  const signer = createSolanaSigner(process.env.SOLANA_PRIVATE_KEY!);
  const paidFetch = wrapFetchWithPayment(fetch, signer);

  const res = await paidFetch(
    "https://api.syntalic.com/v1/shopper/best-price?q=airpods+pro&country=us"
  );
  const data = await res.json();
  ```

  ```ts Base (EVM) theme={null}
  import { wrapFetchWithPayment } from "@x402/fetch";
  import { createEvmSigner } from "@x402/evm";

  const signer = createEvmSigner(process.env.EVM_PRIVATE_KEY!);
  const paidFetch = wrapFetchWithPayment(fetch, signer);

  const res = await paidFetch(
    "https://api.syntalic.com/v1/shopper/best-price?q=airpods+pro&country=us"
  );
  const data = await res.json();
  ```
</CodeGroup>

## Manual integration

If you can't use the SDK, the protocol is two HTTP requests:

```ts theme={null}
// 1. Discovery — call without payment, parse the 402 response
const discovery = await fetch(url).then((r) => r.json());
const { recipient, price, chain } = discovery["x-payment-info"].x402;

// 2. Sign a USDC transfer authorization for `price` USDC to `recipient`
//    on `chain`, bound to this request URL. Format depends on chain.
const xPayment = await signUsdcTransferAuthorization({ recipient, price, chain });

// 3. Retry with the X-Payment header
const response = await fetch(url, {
  headers: { "X-Payment": xPayment },
});
```

The exact signing payload format is defined in the [x402 spec](https://x402.org). Use `@x402/svm/exact/client` or `@x402/evm/exact/client` if you want signing helpers without the fetch wrapper.

## Supported chains

| Chain  | Asset         | Settlement time |
| ------ | ------------- | --------------- |
| Solana | USDC (SPL)    | \~1 second      |
| Base   | USDC (ERC-20) | \~2 seconds     |

The recipient address is returned in the `x-payment-info` discovery block — never hardcode it. We may rotate keys without prior notice.

## Failed payments

If chain settlement fails (insufficient balance, expired authorization, network issue), the API returns `402 Payment Required` with an `error` field describing the cause. Retry with a fresh authorization.
