# Scout Radar — Developer API (v1)

Token-gated, **read-only** HTTP API. Same product data as the Pro web app.

**Billing is prepaid usage tokens — not a monthly subscription.**

- **Docs (HTML):** `/developers`
- **OpenAPI:** `/docs` (tag *Developer API v1*)
- **Buy tokens:** Discord ticket (owner loads your balance)

---

## Pricing (prepaid)

| | |
|--|--|
| Model | Pay once → get **usage tokens** on your API key |
| Minimum | **$5** |
| Rate | **500 tokens per $1** |
| Spend | **List endpoints: 1 token per game in `limit`** (limit=20 → 20 tokens). Single-game endpoints: 1 token. Search: 10. |
| Monthly fee | **None** — balance only goes down as you use it |

### Packs

| Pay | Tokens | ≈ game-rows | ≈ pages at limit=20 |
|-----|--------|-------------|---------------------|
| **$5** (min) | **2,500** | ~2.5k | ~125 |
| $10 | 5,000 | ~5k | ~250 |
| $20 | 10,000 | ~10k | ~500 |
| $50 | 25,000 | ~25k | ~1,250 |

When balance is low → `BALANCE_SOFT` warning.  
When empty → `402 BALANCE_EMPTY` until you top up (again min $5).

Also: **60 requests/minute** hard cap (slower than Pro web) so the API is gentle on the server.

---

## Authentication

```http
Authorization: Bearer sr_live_xxxxxxxx
```

or

```http
X-Api-Key: sr_live_xxxxxxxx
```

Key is shown **once** when minted. Store it like a password.

---

## Base URL

```
https://YOUR_DOMAIN/api/v1
```

---

## Balance & warnings

### Headers (every response)

| Header | Meaning |
|--------|---------|
| `X-SR-Tokens-Remaining` | Prepaid tokens left |
| `X-SR-Tokens-Cost` | Tokens spent this call (lists = page size) |
| `X-SR-Tokens-Per-Usd` | Exchange rate (500) |
| `X-RateLimit-Limit` | Max req/min |
| `X-RateLimit-Remaining` | Left this minute |
| `X-SR-Warning` | Soft warning code(s) |
| `X-SR-Billing` | `prepaid` |
| `Retry-After` | On rate limit |

### Codes

| Code | HTTP | Meaning |
|------|------|---------|
| `BALANCE_SOFT` | 200 | Running low — buy more soon |
| `BALANCE_EMPTY` | **402** | No tokens left — top up |
| `RATE_SOFT` | 200 | Near per-minute limit |
| `RATE_LIMITED` | 429 | Over RPM — wait |
| `TOKEN_*` | 401 | Missing / invalid / revoked / expired key |

Check balance anytime:

```bash
curl -s -H "Authorization: Bearer sr_live_…" \
  https://YOUR_DOMAIN/api/v1/me
```

Look at `token.balance_tokens` and header `X-SR-Tokens-Remaining`.

---

## Endpoints

All authenticated routes return `{ "ok": true, "api": "v1", ... }`.

| Method | Path | Notes |
|--------|------|--------|
| GET | `/api/v1` | Index (no auth) |
| GET | `/api/v1/me` | Key + **balance** |
| GET | `/api/v1/games` | Catalog (max 40/page) |
| GET | `/api/v1/games/{universe_id}` | Detail |
| GET | `/api/v1/games/{universe_id}/history` | Snapshots |
| GET | `/api/v1/potential` | Leaderboard (max 20) |
| GET | `/api/v1/potential/status` | Tier counts |
| GET | `/api/v1/retention` | D1/D7 list |
| GET | `/api/v1/retention/{universe_id}` | One game |
| GET | `/api/v1/blowups` | Growth list |
| GET | `/api/v1/blowups/{universe_id}/ranks` | Ranks |
| GET | `/api/v1/live-speed` | Find/track rates |
| GET | `/api/v1/search?q=` | Live Roblox search |

Retention = public-server playerToken re-sight, **not** official Roblox Analytics.

---

## Example

```python
import requests

BASE = "https://YOUR_DOMAIN/api/v1"
H = {"Authorization": "Bearer sr_live_…"}

r = requests.get(f"{BASE}/potential", params={"tier": "Buy", "limit": 20}, headers=H)
print("tokens left:", r.headers.get("X-SR-Tokens-Remaining"))
print("warn:", r.headers.get("X-SR-Warning"))

if r.status_code == 402:
    raise SystemExit("Out of usage tokens — buy more (min $5)")

r.raise_for_status()
for row in r.json().get("leaderboard") or []:
    print(row.get("game_name"), row.get("tier"), row.get("playing"))
```

---

## Owner ops

Mint / top-up from private console:

- `POST /api/x/{slug}/api-tokens` body `{ "amount_usd": 5, "label": "…", "owner_email": "…" }`
- `POST /api/x/{slug}/api-tokens/topup` body `{ "token_id": 1, "amount_usd": 10 }`
- `POST /api/x/{slug}/api-tokens/revoke`

Env: `SCOUT_API_MIN_PURCHASE_USD` (default `5`).

---

## Support

Discord ticket — say **API tokens $5+** (or $10 / $20 / $50 pack).
