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

# Authentication

> API keys, scopes, and rotation.

## API keys

The Formitto API authenticates with **API keys**. Pass your key as a Bearer
token on every request:

```bash theme={null}
curl https://formitto.com/v1/forms \
  -H "Authorization: Bearer fmt_live_xxxxxxxx"
```

Keys are prefixed `fmt_live_` followed by 43 random characters. They're issued
in the dashboard under **Settings → API keys** and shown in plaintext exactly
once — only a hash is stored, so Formitto can never show you the key again.

A key is scoped to the account that created it (your personal account or your
organization) and can only read or write that account's data.

## Scopes

Each key carries a set of scopes that gate which endpoints it can reach. New
keys default to **read-only**; grant write scopes explicitly when you create
the key.

| Scope               | Grants                        |
| ------------------- | ----------------------------- |
| `read:forms`        | List + read forms             |
| `write:forms`       | Create, update, archive forms |
| `read:submissions`  | List + read submissions       |
| `write:submissions` | Ingest submissions            |
| `read:calendars`    | List + read calendar widgets  |
| `read:bookings`     | List + read bookings          |
| `read:ecommerce`    | List + read shop widgets      |
| `read:orders`       | List + read orders            |

A request to an endpoint your key isn't scoped for returns **HTTP 403** with
`{ "error": "Insufficient scope", "code": "insufficient_scope", "required": "<scope>" }`.

## Errors

Authentication failures return **HTTP 401** with a consistent shape:

```json theme={null}
{ "error": "Unauthorized", "code": "invalid_api_key" }
```

You'll get this when the key is missing, malformed, revoked, or expired.

## Rotation & security

<Warning>
  Treat API keys like passwords. Never commit them to git, embed them in
  client-side code, or paste them into shared docs.
</Warning>

* **Store keys in environment variables** or a secrets manager — never in
  source control.
* **Rotate periodically** (quarterly is a reasonable cadence). Create the new
  key, deploy it, then revoke the old one — there's no downtime because both
  work until you revoke.
* **Revoke immediately** if a key is exposed. Revocation is instant: in the
  dashboard, click **Revoke** on the key. Any integration using it stops
  working at once.
* **Use separate keys per integration** so you can revoke one without
  disrupting the others, and so usage is attributable.
