# Authentication and API keys

> Key format, where to send a key, expiry, rotation, revoking, IP allowlists and keeping keys safe.

Source: https://www.ordstage.com/docs/authentication/

Every request is authenticated with a **workspace API key**. A key belongs to one business, carries a set of
scopes, and works only while that business has API access on its plan.

## Key format

```text
ord_live_<prefix>_<secret>     reaches the business's real data
ord_test_<prefix>_<secret>     reaches the business's test workspace (see Sandbox)
```

- `<prefix>` is 12 hexadecimal characters. It identifies the key in the dashboard and in logs; it is not secret.
- `<secret>` is 43 random characters (256 bits). Ordstage keeps only a keyed hash of the whole key, so nobody,
  including Ordstage, can show it to you again after it is created.
- Older keys look like `ord_<prefix>_<secret>` (no `live`/`test`). They keep working as live keys.

## Sending the key

Send the key in a header on every request. Either form works:

```bash [Authorization]
curl https://api.ordstage.com/v1/calendars \
  -H "Authorization: Bearer $ORDSTAGE_API_KEY"
```

```bash [X-Api-Key]
curl https://api.ordstage.com/v1/calendars \
  -H "X-Api-Key: $ORDSTAGE_API_KEY"
```

> **Never put a key in a URL.** A request with a key in its query string is refused with
> `400 api_key_in_url`, and **the key is revoked immediately**, because addresses end up in browser history, proxy
> logs and analytics. Create a new key if this happens.

Every authentication failure (unknown, malformed, revoked or expired key, an address that isn't allowed, a
dashboard login token) gets the same answer, `401 invalid_api_key` with `WWW-Authenticate: Bearer`, so the
answer never tells anyone which part was wrong. Check the key in **Settings → Developers**, where each key shows
when and from where it was last used.

More than 20 failed authentications in a minute from one address block that address for 15 minutes
(`429 too_many_invalid_keys`).

## Scopes

A scope is `<area>:read` or `<area>:write`, for example `bookings:read`. A key may use a scope only while all of
these hold, checked on every request:

- the key has the scope;
- the business still has the feature behind it (for example a bookings module) — otherwise `403 module_not_active`;
- the business's plan includes API access and that scope — otherwise `403 plan_upgrade_required` or
  `403 api_access_not_allowed`.

Nothing on the key changes when a feature is turned off; turning it back on restores the key. A key without the
scope gets `403 insufficient_scope`, with the missing scope in `param`.

You can also limit a bookings key to some calendars when you create it. Calendars outside that list answer
`404`, as if they did not exist.

## Expiry

When you create a key, choose how long it works: 30, 90 or 365 days, a date of your choice (up to three years), or
no expiry. A key that expires within 7 days is marked **Expiring** in Settings → Developers. An expired key
answers `401 invalid_api_key`. Prefer keys that expire, and rotate them before they do.

## Rotation

**Rotate** gives a key a new secret and keeps everything else (name, scopes, allowlist, history). You choose an
overlap of 0 to 7 days during which the old secret keeps working, so you can deploy the new one without downtime:

1. Rotate the key in **Settings → Developers** with an overlap (for example 1 day). Copy the new secret.
2. Deploy the new secret to your systems.
3. Check the key's activity: once requests only use the new secret, you're done. The old secret stops working when
   the overlap ends.

## Revoking

Revoke a key you no longer need, or at once if it may have leaked (choose the reason "compromised"). Revoking
takes effect on the next request. Revoked keys can't be restored; create a new one.

## IP allowlist

A key can be limited to a list of addresses or ranges in CIDR form (up to 20, for example `203.0.113.0/24`). A
request from any other address is refused with the same `401 invalid_api_key` as any other failure. Use this for
server-to-server integrations with fixed outbound addresses.

## Keeping keys safe

- Keep keys on your servers. Never put a live key in a browser, mobile app or public repository.
- Store keys in a secret manager or environment variables, not in code.
- Use one key per system, with only the scopes it needs, so you can revoke one without stopping the others.
- Use test keys (`ord_test_`) for development, CI and the [API reference's Try it](https://www.ordstage.com/docs/reference/).
- Never share a key in email, chat or a support ticket. Ordstage support will never ask for it; share the
  `Request-Id` instead.
- Keys can't manage keys, billing, the plan, ownership, passwords or webhook secrets, so a leaked key can't take
  over the account. Revoke it anyway.
