> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).

# Rotate API keys

Keep your app secure by regularly rotating API keys when they expire or are exposed.

---

API key rotation is the process of replacing existing API keys with new ones. By setting expiry dates and creating new keys before old ones expire, you can minimize the risk of API keys being compromised without disrupting your app.

Regularly rotating API keys is good practice, and helps protect your account from unauthorized access.

You can rotate keys two ways: **automatically** with AWS Secrets Manager, or **manually** by creating a new key and transitioning to it yourself. This guide covers both.

## Automatic rotation with AWS Secrets Manager {% id="aws-secrets-manager" %}

If you store your Paddle API keys in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html), you can rotate them automatically on a schedule. Paddle is an official AWS Secrets Manager partner, so rotation happens inside AWS without you swapping keys by hand. This works with both live and sandbox keys, with no need to configure which environment you're using.

{% callout type="note" %}
Automatic rotation only works for keys marked as rotatable when you create them. [Create a rotatable API key](https://developer.paddle.com/api-reference/about/authentication#rotatable.md) before you set up rotation in AWS Secrets Manager.
{% /callout %}

### How automated rotation works

When AWS Secrets Manager rotates your key, Paddle automatically:

1. Generates a new secret for your API key. It's shared with AWS Secrets Manager but isn't active yet.
2. Activates the new secret the first time it's used to authenticate a request.
3. Keeps the old secret valid for a grace period, so requests already using it keep working during the switch.
4. Revokes the old secret once the grace period ends.

Because both secrets are valid during the grace period, your app keeps working throughout rotation with no downtime. If you need an atomic rotation for compliance reasons, you can set the grace period to 0.

### Set up rotation in AWS Secrets Manager

1. [Create a rotatable API key](https://developer.paddle.com/api-reference/about/authentication#rotatable.md) in Paddle.
2. Store the key as a secret in AWS Secrets Manager.
3. Enable rotation for the secret and select Paddle as the rotation integration. See the [AWS Secrets Manager rotation guide](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html) for the exact steps in the AWS console.

{% callout type="warning" %}
If you try to rotate a key that wasn't created as rotatable, rotation fails. [Create a new rotatable key](https://developer.paddle.com/api-reference/about/authentication#rotatable.md) and use that instead.
{% /callout %}

### How rotation affects expiry {% id="expiry-and-rotation" %}

Rotating a key extends its [expiry](https://developer.paddle.com/api-reference/about/authentication#expiration.md). When AWS Secrets Manager rotates a key, Paddle sets the new expiry to the time of rotation, plus the number of days until the next scheduled rotation and a one-day buffer. As long as a key keeps rotating on schedule, it never reaches a fixed expiry date.

Because expiry is tied to the rotation schedule, keep the two aligned:

- **Rotate as soon as you store the key in AWS Secrets Manager.**  
  This is a native part of the Secrets Manager setup. An immediate rotation aligns the expiry with your rotation schedule right away, and sets an expiry if the key doesn't have one yet.
- **Rotate immediately if you make rotations less frequent.**  
  If you increase the rotation interval in AWS Secrets Manager, run an immediate rotation so the expiry realigns. Shortening the interval doesn't require this, but it doesn't hurt.
- **Don't edit the expiry in the Paddle dashboard.**  
  If you change it manually, run an immediate rotation so AWS Secrets Manager can realign it.

{% callout type="warning" %}
If a key's expiry is ever earlier than its next scheduled rotation, the key can expire before it's rotated. Following the steps above keeps the expiry and rotation schedule aligned so this doesn't happen.
{% /callout %}

## Manual rotation

You can build your own workflow to rotate API keys manually in the Paddle dashboard. This is useful if you don't want to use AWS Secrets Manager or if you need more control over the rotation process.

### Before you begin

- [Create an API key](https://developer.paddle.com/api-reference/about/authentication.md) with an expiry date. If an API key has no expiry date, you can still rotate keys but you aren't notified when the key is about to expire.
- Set up webhooks for when a key is about to expire, has expired, or is exposed. You can subscribe to [`api_key.expiring`](https://developer.paddle.com/webhooks/api-keys/api-key-expiring.md), [`api_key.expired`](https://developer.paddle.com/webhooks/api-keys/api-key-expired.md), [`api_key_exposure.created`](https://developer.paddle.com/webhooks/api-keys/api-key-exposure-created.md), and [`api_key.revoked`](https://developer.paddle.com/webhooks/api-keys/api-key-revoked.md) notifications.

When you receive an `api_key.expiring` or `api_key.revoked` webhook, you should rotate your API key as soon as possible.

### Overview

Rotating your API keys follows this workflow:

1. [**Create a new API key**](https://developer.paddle.com/api-reference/about/rotate-api-keys#create-new-key.md)  
   Grab a new key immediately or before the current one expires.
2. [**Store and use the new key**](https://developer.paddle.com/api-reference/about/rotate-api-keys#store-use-key.md)  
   Transition to using the new key in your app.
3. [**Check API key activity**](https://developer.paddle.com/api-reference/about/rotate-api-keys#check-api-key-activity.md)  
   Verify the new key works and the old key is no longer used.
4. [**Revoke the old key**](https://developer.paddle.com/api-reference/about/rotate-api-keys#revoke-old-key.md)  
   Stop the old key from working and remove it.

### Use an AI agent

Use these prompts with an AI agent to set up key rotation, react to webhooks, or respond to an exposure.

### Create a new API key {% step=true id="create-new-key" %}

When you receive an `api_key.expiring` or `api_key.revoked` webhook, you should create a new API key as soon as possible. Plan for an overlap period between old and new keys to allow for a smooth transition without disruption to your app.

{% callout type="warning" %}
If you're rotating due to an exposure, prioritize security over convenience and consider [revoking the exposed key](https://developer.paddle.com/api-reference/about/authentication.md) first.
{% /callout %}

When creating a new API key:

- Assign the same [permissions](https://developer.paddle.com/api-reference/about/permissions.md) as the current key.
- Set an appropriate expiry date.
- Add a descriptive name that includes its purpose, team if applicable, and expiry date for easier management.

### Store and use the new API key {% step=true id="store-use-key" %}

Store the key safely and replace the old key in all places where your app uses it.

{% callout type="note" %}
We recommend using a key management system with version control to track changes to your API keys. This makes it easier to manage key rotation and revert changes if needed.
{% /callout %}

Store both your new and old API keys so they're available at the same time. Set up your code to try the new key first, but use the old key as a backup if anything goes wrong.

1. Create a new `ACTIVE_PADDLE_KEY` and `OLD_PADDLE_KEY` environment variable or key in your key management system.
2. Set the new key as `ACTIVE_PADDLE_KEY`.
3. Move the old key to `OLD_PADDLE_KEY` temporarily.
4. Update your code to use either `ACTIVE_PADDLE_KEY` or `OLD_PADDLE_KEY` as the Paddle API key.

This means your app keeps working during the switch, allows testing the new key in real conditions, and provides a fallback if the new key causes problems.

{% code-group sync="sdk-language-preference" %}

```javascript {% title="Node.js" wrap=true %}
const ACTIVE_PADDLE_KEY = process.env.ACTIVE_PADDLE_KEY || process.env.OLD_PADDLE_KEY;
```

```python {% title="Python" wrap=true %}
ACTIVE_PADDLE_KEY = os.getenv("ACTIVE_PADDLE_KEY") or os.getenv("OLD_PADDLE_KEY")
```

```php {% title="PHP" wrap=true %}
$activePaddleKey = getenv("ACTIVE_PADDLE_KEY") ?: getenv("OLD_PADDLE_KEY");
```

```go {% title="Go" wrap=true %}
activePaddleKey := os.Getenv("ACTIVE_PADDLE_KEY")
if activePaddleKey == "" {
    activePaddleKey = os.Getenv("OLD_PADDLE_KEY")
}
```

{% /code-group %}

### Check API key activity {% step=true %}

After updating your app to use the new key, check that:

- **The new key is working properly**  
  Test the integration to verify that requests using the new API key are successful. Look at logs, errors, latency, and other metrics to ensure the new key is working properly.
- **The old key is no longer being used**  
  [Check the last used date](https://developer.paddle.com/api-reference/about/authentication.md) of the old API key in **Paddle > Developer Tools > Authentication**. If the date hasn't changed since the update, it indicates that the old key is no longer being used anywhere in your app.

### Revoke the old key {% step=true id="revoke-old-key" %}

Once you've verified that your app is successfully using the new key and the old key is no longer in use, you can safely [revoke the old API key](https://developer.paddle.com/api-reference/about/authentication.md) instead of waiting for it to expire.

Keep checking your logs to ensure there are no errors upon revoking the old key.

{% callout type="info" %}
If a key is accidentally revoked while still in use or errors appear in logs, there is a 60-minute grace period to [reactivate the API key](https://developer.paddle.com/api-reference/about/authentication.md). Reactivation isn't possible if the key was revoked due to an exposure.
{% /callout %}

If everything is working as expected, you can safely remove the old key from your key management system, environment variables, or any other places where it's stored. This includes the value of the `OLD_PADDLE_KEY` if you opted to use two keys simultaneously when switching.