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

# Authentication

> Authenticate to the ScripX API with the X-ScripX-Key header: how keys are issued, the scope model, per-plan rate limits, and the exact X-RateLimit response headers on every call.

Every request authenticates with a single header over HTTPS:

```bash theme={"dark"}
X-ScripX-Key: scripx_live_…
Content-Type: application/json
```

A key is bound to one firm; tenant isolation is enforced on every call. Keys are shown once at issue and stored only as salted hashes: keep yours somewhere safe.

## Getting a key

* **Your firm key** is issued by ScripX. Write to [amin@eximfiles.io](mailto:amin@eximfiles.io) for a sandbox key to build against, and again when you are ready for production.
* **Child keys** you mint yourself with [`POST /v1/keys`](/api-reference/keys/create): one per sub-account or app, each carrying a subset of your scopes. Revoke any of them at any time without touching the parent.
* **Sandbox keys** carry the `scripx_test_` prefix and are unmetered. See [Environments](/environments).

<Warning>
  Keep API keys server side. Never ship a key in a mobile app, a browser bundle, or a public repo. If a key leaks, revoke it and re-issue; the old hash stops matching immediately.
</Warning>

## Scopes

Each key carries scopes; each endpoint demands one. A child key's scopes are always a subset of its parent's.

| Scope            | Grants                                                                                  |
| ---------------- | --------------------------------------------------------------------------------------- |
| `firms`          | registering client firms and reading their connection state                             |
| `quote`          | `POST /v1/quote`, `POST /v1/cross/quote`                                                |
| `orders:write`   | placing orders, funding and releasing crosses                                           |
| `orders:read`    | orders, positions, group netting reads, cross reads, earnings, statements, audit export |
| `market:read`    | market snapshots and the SSE stream                                                     |
| `webhooks:write` | registering and managing webhooks                                                       |
| `*`              | everything above                                                                        |

## Authentication errors

| HTTP | Slug           | Why                                                                |
| :--: | -------------- | ------------------------------------------------------------------ |
|  401 | `unauthorized` | Header missing, key unknown, revoked, or the wrong environment     |
|  403 | `forbidden`    | Key valid but lacks the endpoint's scope, or acts outside its role |
|  429 | `rate_limited` | Per-minute rate or monthly quota exceeded                          |

The body is the standard flat error shape. Read the stable slug as `code ?? error` and branch on that, never on `message`; the `X-Request-ID` response header correlates any failure to its server-side log. See [Errors](/errors).

## Rate limits

Every key carries a monthly call quota and a per-minute rate. Sandbox keys are unmetered. Every response tells you exactly where you stand:

| Header                   | Meaning                                    |
| ------------------------ | ------------------------------------------ |
| `X-RateLimit-Plan`       | The key's plan name                        |
| `X-RateLimit-Limit`      | Calls allowed per 60-second sliding window |
| `X-RateLimit-Remaining`  | Calls left in the current window           |
| `X-RateLimit-Reset`      | Seconds for the window to fully clear      |
| `X-RateLimit-Quota`      | Monthly call quota (absent when unmetered) |
| `X-RateLimit-Quota-Used` | Calls consumed this month                  |
| `Retry-After`            | On a 429 only: seconds to back off         |

Back off on `Retry-After` instead of guessing; the window is sliding, so hammering resets nothing.

## Related

* [Errors](/errors), the full error contract.
* [Keys](/api-reference/keys/create), self-serve child keys.
* [Usage](/api-reference/account/usage), the same numbers as JSON.
