# Authentication

> Authenticate with a Skylit API key, and how credits and rate limits work.

> **Beta.** The API and MCP server are open to members with API access. Check yours on the [Developer page](https://app.skylit.ai/developer).

The Skylit Public API uses **bearer authentication**. Send your API key in the
`Authorization` header on every request:

```bash
Authorization: Bearer <your-api-key>
```

> **Note:** REST endpoints read only the `Authorization` header. A request without it gets
> `401 Authorization field missing`; an invalid, revoked or expired key gets `403`.
> The MCP server uses the same header. `X-API-Key` and query-string keys are not
> read (`401`). The gateway also accepts the bare key without the `Bearer ` prefix;
> `Bearer` is the documented form.

> **Warning:** Treat API keys like passwords. Never commit them to source control or expose them in
> client-side code. Use environment variables and rotate keys if one leaks.

## Getting a key

Generate and manage keys on the [Developer page](https://app.skylit.ai/developer) (API keys tab). New accounts
start with the credits their plan includes (see [Plans and credits](https://www.skylit.ai/docs/api-reference/plans-and-credits)); `GET /v1/account` shows the balance.
MCP clients such as Claude, Claude Code and Cursor can also sign in with Skylit
(OAuth) instead of using a key: see the [MCP quickstart](https://www.skylit.ai/docs/mcp/quickstart).

```bash cURL
curl "https://api.skylit.ai/v1/heatmap?symbols=SPY" \
  -H "Authorization: Bearer $SKYLIT_API_KEY"
```

```python Python
import os, requests

session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['SKYLIT_API_KEY']}"
print(session.get("https://api.skylit.ai/v1/heatmap", params={"symbols": "SPY"}).json())
```

```javascript Node
const skylit = (path) =>
  fetch(`https://api.skylit.ai${path}`, {
    headers: { Authorization: `Bearer ${process.env.SKYLIT_API_KEY}` },
  }).then((r) => r.json());

console.log(await skylit("/v1/heatmap?symbols=SPY"));
```

## Credits

Every chargeable request debits a fixed cost from your credit balance
(1 credit = $0.001). Each endpoint's cost is shown on its API Reference page
(`x-credits` in the OpenAPI specs). `/v1/account` and `/v1/openapi.json` are
free. Streams charge to open and then per symbol per minute; the `connected`
event states the rate.

Every chargeable response carries `X-Credits-Remaining: <balance>`.
**Failed calls are free:** a request answered with any `4xx` or `5xx` is refunded,
and its `X-Credits-Remaining` already reflects the refund.

- **402 insufficient_credits**: You're out of credits. Buy a credit pack on the [Developer page](https://app.skylit.ai/developer) (Community and up), or wait for your plan's Monthly API Credits to reset on the 1st (ET). See [Plans and credits](https://www.skylit.ai/docs/api-reference/plans-and-credits).
- **402 monthly_cap_reached**: Your account's monthly spend cap was reached. Contact support to raise it.
- **403 account_suspended**: The account has been administratively suspended.

## Rate limits

Each key has a requests-per-minute limit set by your plan, shared across all
Skylit APIs. `GET /v1/account` returns it (`limits.requestsPerMinute`) along with
your other limits, so read it rather than hard-coding a number.

Every response carries the key's current window:

| Header | Meaning |
| --- | --- |
| `X-RateLimit-Limit` | Requests allowed per minute on this key |
| `X-RateLimit-Remaining` | Requests left in the current window |
| `X-RateLimit-Reset` | When the window resets (Unix seconds) |

| Status | Meaning |
| --- | --- |
| `401 Unauthorized` | Missing or invalid API key. |
| `403 Forbidden` | Key revoked/expired, or account suspended. |
| `429 Too Many Requests` | Rate limit hit (`rate_limited`). The gateway's `429` has no `Retry-After`: wait until `X-RateLimit-Reset`, then retry with jitter. `429`s from the API itself (concurrency or stream limits) carry `Retry-After`. |

For backoff code and the full retry rules, see [Rate limits and retries](https://www.skylit.ai/docs/api-reference/rate-limits-and-retries). Every error code is listed on [Errors](https://www.skylit.ai/docs/api-reference/errors).

- [Make your first call](https://www.skylit.ai/docs/api-reference/heatmap/live-per-strike-heatmap-one-or-more-symbols): Jump to **GET /v1/heatmap** and try it live in the playground.
