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

# Rate limits and access

> Per-IP limits, headers and access during the alpha.

```bash theme={null}
BASE_URL="https://api.lucidblock.xyz"
```

## Limits

| Limit | Value |
| - | - |
| Rate limit | **60** units per 60 s per IP |
| Wallet read (`/v1/solana/wallets/{wallet}/defi-positions`) | **5** units |
| Everything else under `/v1` (job status, protocols, coverage, health) | 1 unit |
| `/`, `/openapi.json`, CORS preflights | free |
| New scans (`cold_scan_limit`) | 20 job-creating requests per IP per hour |

When the per-IP budget is spent you get `429 RATE_LIMITED` with `details.reason: "per_ip_rate"`. When a request would
start a new scan and your IP has already started 20 this hour, you get `429` with `details.reason: "cold_scan_limit"`;
wallets that already have a snapshot still load.

## Headers

Every rate-limited response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds until the
window resets). A `429` adds `Retry-After`. CORS exposes all of them to browsers.

A captured `429`:

> [accordion] Captured example
>
> `GET /v1/solana/coverage` → `429` (captured 2026-11-12 from local `error-rate-limited`)
>
> ```json theme={null}
> {
>   "error": {
>     "code": "RATE_LIMITED",
>     "message": "rate limit exceeded",
>     "details": {
>       "limit": 60,
>       "retry_after_s": 44
>     }
>   },
>   "request_id": "0d54ba7c-7273-460a-9fe3-ceb8bddf12ad"
> }
> ```

## Staying within the limit

* Poll the job (1 unit), not the wallet (5 units), after a `202`.
* Cache responses per `Cache-Control` (`/v1/solana/protocols` and `/v1/solana/coverage` for 60 s).
* Don't set `freshness_seconds=0` routinely: it forces a refresh scan each time and can hit `cold_scan_limit`.
* Spread a large wallet list over time; watch `RateLimit-Remaining` and pause on `Retry-After`.

## Access during the alpha

The API runs in private alpha with an access token (the server-side `PRIVATE_API_TOKEN` gate): every `/v1/*` route
except `/v1/health` needs `Authorization: Bearer <token>`. Request a token at `<CONTACT_EMAIL>`. Keep it server-side in
public apps: anyone with the token spends your limits. There are **no API keys** or paid tiers in v1; the limits above
apply per IP to everyone.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.