# Quickstart (5 minutes)

## Goal

Make a request, receive a `402` challenge, then **pay and retry** to get a `200` response.

### Prerequisites

* A wallet funded with **USDC** on **Base** or **Solana** (v2 endpoints support both; v1 is Base/EVM-only).
* A runtime (Node.js 18+ or Python) and a safe place to store a private key (never commit it).

### 1) Trigger a `402` challenge

Use `-i` so you can see the `PAYMENT-REQUIRED` header:

```bash
curl -i https://sentiment-api.kytona.com/v2/snapshot/global
```

You’ll receive `402 Payment Required` plus:

* Header: `PAYMENT-REQUIRED` (source of truth)
* Body: a JSON representation of the same requirements (for convenience)

### 2) Pay and retry (TypeScript, Base/EVM)

```bash
npm i @x402/core @x402/evm
```

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

const url = "https://sentiment-api.kytona.com/v2/snapshot/global";

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 {
  // Some clients/proxies strip bodies; fall back to decoding the header.
}
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", // Base mainnet
});
const { encodedSignature } = await scheme.sign(requirements);

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

const data = await paid.json();
console.log(data.cryptoPulse.moodIndex);
```

#### Solana/SVM (v2 only)

```bash
npm i @x402/core @x402/svm
```

```ts
import { decodePaymentRequiredHeader } from "@x402/core/http";
import { ExactSvmScheme } from "@x402/svm";

const url = "https://sentiment-api.kytona.com/v2/snapshot/global";
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 ExactSvmScheme({
  privateKey: process.env.SOLANA_PRIVATE_KEY!,
  network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
});
const { encodedSignature } = await scheme.sign(requirements);
const paid = await fetch(url, { headers: { "PAYMENT-SIGNATURE": encodedSignature } });
console.log(await paid.json());
```

### 3) Make it cheaper to run (compact trading format)

For trading/bot loops, request the compact payload:

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

### Troubleshooting

* `400 INVALID_FORMAT`: `format` only supports `compact_trading` (omit `format` for the full response).
* `400 INVALID_COMPACT_FIELDS`: use the allowlist shown in Endpoints.
* `402` even after paying: ensure you are using the **v2** header name `PAYMENT-SIGNATURE` and that you signed the **same** requirements you were challenged with.
* `429 RATE_LIMITED`: back off and retry after the `retry_after` value.
