> For the complete documentation index, see [llms.txt](https://developers.gallantreecapital.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.gallantreecapital.com/guides/key-rotation.md).

# Key rotation and expiry

API keys are meant to be rotated, not held forever. This guide covers how expiry works, when the portal warns you, and the overlap-window pattern for rotating without downtime.

## Expiry defaults

* **Default lifetime:** 90 days from creation.
* **Maximum lifetime:** 90 days — a compliance ceiling. The portal will not let you issue a key with a longer expiry.
* **Warning window:** the portal (and the app's Credentials page) warns you **14 days** before a key expires. Wire your CI / observability to alert on the same signal — grep your codebase for the key prefix, cross-reference the portal's expiry date, and page yourself when the delta drops under two weeks.
* **Maximum active keys per app:** 5. You'll always have room to run an overlap window; you won't accidentally rotate a key without cleaning up the old ones.

Once a key expires, the API returns `401 API key has expired` on every request that uses it. There is no grace period on an already-expired key — regenerate first.

## The overlap-window pattern

The point of rotation is to swap a credential without dropping a single request. The pattern:

1. **Generate a new key** in the portal (the existing key stays valid).
2. **Deploy** the new key alongside the old one — your integration reads whichever the config specifies. Some teams add a bit of config that tries the new key and falls back to the old; others rotate atomically by updating a single environment variable.
3. **Wait for propagation** — depending on your fleet, minutes to hours. The old key is still valid throughout.
4. **Revoke the old key** in the portal.

The platform's default **rotation grace** is **24 hours**: after you generate a new key, the portal reminds you to revoke the old one within 24 hours. Nothing enforces this — it's a nudge, not a limit — but treat it as the SLO.

## Revocation is immediate

When you revoke a key in the portal, the next request that uses it is rejected. There's no CDN cache, no async propagation delay. If you revoke a key you're still using in production, expect immediate `401`s.

## What happens on expiry

* Requests using the key get `401 API key has expired`.
* The key does **not** auto-renew. You must generate a new one — the existing key is inert.
* Other keys on the same app are unaffected.
* Webhook deliveries continue — webhook signing uses the subscription's signing secret, not the app's API key.

## Programmatic checks

You can inspect an app's keys — including their `expiresAt`, `lastUsedAt`, and `revokedAt` timestamps — via the portal's own admin API (used by the portal UI). If you want to build a "rotation health" dashboard for your integration, poll it hourly.

## Runnable example — rotate without downtime

```bash
# 1. Read the current key from your secret store (whatever your team uses)
OLD_KEY=$(vault kv get -field=api-key secret/gallantree)

# 2. Generate NEW_KEY in the portal, copy it into your secret store
vault kv put secret/gallantree api-key="$NEW_KEY"

# 3. Deploy — depending on your rollout style, this may be a rolling restart
kubectl rollout restart deployment/gallantree-sync

# 4. Verify the new key is live everywhere by tailing your logs for the prefix
kubectl logs -l app=gallantree-sync | grep "$(echo "$NEW_KEY" | cut -c1-12)"

# 5. Revoke the old key in the portal
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers.gallantreecapital.com/guides/key-rotation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
