Skip to content

API Key Rotation

An API key that stays unchanged for years eventually ends up somewhere you didn't intend -- a log file, a screenshot, an old repository. Rotating your keys on a schedule limits how much damage a leaked key that nobody noticed can still do.

Rotation creates a new key and lets the old one keep working for a limited overlap window, so you can roll the new key out without downtime.

When to rotate

  • Routinely, every 90 days. This is the recommended baseline for production keys.
  • Immediately, whenever you suspect a key may have leaked -- committed to a repository, pasted into a support ticket, visible in a screenshot. Don't wait for the next scheduled rotation.

How it works

Rotation is a four-step process:

  1. Trigger the rotation. In the Dashboard, go to API Keys and choose Rotate on the key you want to replace. You can also call the rotation endpoint directly (see below). Both the old key (the predecessor) and the new key (the successor) work during the overlap window that follows.
  2. Roll out the new key to whatever service or script used the old one. The successor inherits the predecessor's name, scopes, and environment, so no configuration changes beyond swapping the key value are needed.
  3. Check the "Last used" column for the old key once the rollout is complete. This is how you confirm the migration actually worked: if the column keeps advancing, something is still calling the API with the old key, and you should track it down before the window closes.
  4. Let the window expire. Once you've confirmed the old key is idle, there's nothing further to do -- it stops working automatically at the end of the overlap window. You don't need to revoke it manually.

Don't guess -- check 'Last used'

"Last used" is the only reliable signal that a rotation is safe to let finish. Rotating and immediately walking away means finding out about a forgotten integration only after it starts failing.

Triggering a rotation via the API

curl -X POST https://api.subscribeflow.net/api/v1/api-keys/KEY_ID/rotate \
  -H "X-API-Key: sf_live_..." \
  -H "Content-Type: application/json" \
  -d '{"overlap_days": 7}'

overlap_days is optional and accepts 1-90; if you omit it, the platform default applies (query it via GET /api/v1/api-keys/rotation-defaults). The response contains the successor's plain-text key and a rotated_from block describing the predecessor -- this is the only time the new key's plain text is shown, so store it the same way you would a freshly created key.

The successor also inherits the predecessor's expiration: if the predecessor had a fixed lifetime (say, 90 days from when it was created), the successor gets the same duration counted from the moment of rotation. If the predecessor never expired, the successor doesn't either.

What the response headers tell you

Once a key has an expiry date that hasn't passed yet, every response authenticated with it carries three headers:

Header Meaning
Sunset The date the key stops working, as an HTTP date
Deprecation Always true while the key carries an expiry date in the future -- whether or not it was rotated
X-API-Key-Expires-In-Days Days remaining until the key stops working

All three are readable from browser clients as well (they're on the CORS-exposed header list), so a frontend integration can surface the warning without a server-side proxy.

curl -i https://api.subscribeflow.net/api/v1/subscribers?limit=1 \
  -H "X-API-Key: sf_live_..."

# HTTP/1.1 200 OK
# Sunset: Wed, 04 Nov 2026 00:00:00 GMT
# Deprecation: true
# X-API-Key-Expires-In-Days: 7

If you see these headers on a key you didn't expect to expire, check the Dashboard -- it may already have been rotated.

Notification

By default three days before a key expires, SubscribeFlow sends one reminder email to each of the organization's Owners (the lead time is configurable server-side, and the run happens once a day). It's a backstop, not a replacement for checking "Last used" yourself -- by the time it arrives you should already know whether the rollout succeeded.

Limits

  • The plain-text key is shown exactly once -- at creation and again at rotation. If you lose it, rotate the key to get a new one; there's no way to retrieve a lost key's plain text.
  • A key can be rotated exactly once while its successor exists. If you need to rotate again, rotate the successor, not the original key. Attempting to rotate an already-rotated, revoked, or expired key returns an error.
  • The window can come out shorter than requested. If the predecessor already carried an expiry date, the earlier of the two wins: asking for overlap_days: 30 on a key that expires in two days gives you two days. The rotated_from block in the response states the actual expiry.
  • The overlap window is fixed at the moment of rotation and can't be extended afterwards. There's no way to give the predecessor more time once the rotation has happened -- rotating the successor doesn't change the predecessor's expiry either. If you expect a longer rollout, choose a larger overlap_days value when you trigger the rotation.