# Using the API Key API

Zuplo runs a globally distributed API Key management service that scales to
handle billions of daily key validation requests while maintaining low latency
from any region around the world.

Management of API Keys and consumers
[can be performed in the Zuplo Portal](./api-key-management.mdx) and for
end-users in the Zuplo Developer Portal. However, all management operations
regarding API Keys can also be performed using the
[Zuplo Developer API](https://zuplo.com/docs/api/api-keys-keys).

:::tip{title="Building API key management into your product?"}

If you want to add self-serve API key creation, rotation, and deletion to your
own application's UI, see
[Build Self-Serve API Key Management in Your Product](./api-key-self-serve-integration.mdx)
for a complete implementation guide with architecture, code examples, and
security guidance.

:::

:::info

In order to obtain an API Key for the Developer API, go to your account settings
in the Zuplo Portal. [More information](./accounts/zuplo-api-keys)

:::

## Models

The service contains three primary object: **Buckets**, **Consumers**, and **API
Keys**. For a conceptual overview of these objects see
[Key Concepts](./api-key-management#key-concepts). Below is an ER diagram
showing the relationships of the three primary objects and their most important
fields.

The Consumer is the most important object. Each consumer is in a bucket.
Consumers can contain one or more API Keys.

### Buckets

Buckets are the top level group for this service. A bucket could be used with a
single Zuplo environment or shared among multiple environments or projects. By
default a Zuplo API Gateway project will be created with several buckets that
map to production, preview, and development (working copy) environments.

Enterprise plan customers run complex configurations where buckets are shared
across gateway projects or even accounts. This can allow your end-users to
authenticate to all your APIs with a single API key with unified permissions.

### Consumers

Consumers are the core of the API Key service. The consumer is the "identity" of
any API Keys that are created. Consumers have a `name` which must be unique in
the bucket. This `name` is used as the default `user.sub` property in the API
Key Authentication policy.

### API Keys

A Consumer can have any number of API keys associated with it. Each API Key
shares the same identity (for example Consumer) when authenticating with this
service. Expired keys won't be permitted to authenticate after their expiration.

:::tip

In most cases, you won't manage API Keys directly. When using the API, the
typical configuration is to create a consumer with an API key and each consumer
has only a single API key except when performing operations like rolling keys.

:::

## Usage

This section explains common scenarios for managing API keys using the API. For
other uses, see the full [Developer API reference](https://dev.zuplo.com).

All examples assume two environment variables are set (in your terminal, not
inside Zuplo)

```bash
# Your Zuplo Account Name
export ACCOUNT_NAME=my-account
# Your bucket API URL (Found in Settings > General)
export BUCKET_NAME=my-bucket
# Your Zuplo API Key (Found in Settings > Zuplo API Keys)
export ZAPI_KEY=zpka_YOUR_API_KEY
```

### Creating a Consumer with a Key

When creating a new Consumer, it's a good idea to include some useful metadata
like the `organizationId` or a particular `plan` that's associated with that
user.

Tags are used for querying the consumers later. It's often useful to store some
external identifier that links this consumer to your internal data as a tag.

```shell
curl \
  https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_NAME/consumers?with-api-key=true \
  --request POST \
  --header "Content-type: application/json" \
  --header "Authorization: Bearer $API_KEY" \
  --data @- << EOF
{
  "name": "my-consumer",
  "description": "My Consumer",
  "metadata": {
    "orgId": 1234,
    "plan": "gold"
  },
  "tags": {
    "externalId": "acct_12345"
  }
}
EOF
```

The response will look like this:

```json
{
  "id": "csmr_sikZcE754kJu17X8yahPFO8J",
  "name": "my-consumer",
  "description": "My Consumer",
  "createdOn": "2023-02-03T21:33:17.067Z",
  "updatedOn": "2023-02-03T21:33:17.067Z",
  "tags": {
    "externalId": "acct_12345"
  },
  "metadata": {
    "orgId": 1234,
    "plan": "gold"
  },
  "apiKeys": [
    {
      "id": "key_AM7eAiR0BiaXTam951XmC9kK",
      "createdOn": "2023-06-19T17:32:17.737Z",
      "updatedOn": "2023-06-19T17:32:17.737Z",
      "expiresOn": null,
      "key": "zpka_d67b7e241bb948758f415b79aa8exxxx_2efbxxxx"
    }
  ]
}
```

You can use this API Key to call your Zuplo API Gateway that's protected by the
[API Key Authentication](/docs/policies/api-key-inbound) policy.

### Query Consumers with API Keys By Tags

```shell
export ORG_ID=1234
curl \
  https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_NAME/consumers/?include-api-keys=true&key-format=visible&tag.orgId=$ORG_ID \
  --header "Authorization: Bearer $API_KEY"
```

The response will look like this:

```json
{
  "data": [
    {
      "id": "csmr_sikZcE754kJu17X8yahPFO8J",
      "name": "my-consumer",
      "description": "My Consumer",
      "createdOn": "2023-02-03T21:33:17.067Z",
      "updatedOn": "2023-02-03T21:33:17.067Z",
      "tags": {
        "externalId": "acct_12345"
      },
      "metadata": {
        "orgId": 1234,
        "plan": "gold"
      },
      "apiKeys": [
        {
          "id": "key_AM7eAiR0BiaXTam951XmC9kK",
          "createdOn": "2023-06-19T17:32:17.737Z",
          "updatedOn": "2023-06-19T17:32:17.737Z",
          "expiresOn": null,
          "key": "zpka_d67b7e241bb948758f415b79aa8exxxx_2efbxxxx"
        }
      ]
    }
  ],
  "offset": 0,
  "limit": 1000
}
```

### Roll a Consumer's Keys

Key rotation is a critical part of API key lifecycle management. Instant
revocation of a key can break every system that depends on it, so Zuplo supports
**rolling transitions** — creating a new key while keeping the old key active
for a defined grace period.

When you call the roll key endpoint, Zuplo:

1. Creates a new key with no expiration for the consumer
2. Sets the `expiresOn` date on all existing keys to the value you specify

This gives consumers time to update their integration to the new key before the
old one stops working.

#### Choosing a transition period

The right `expiresOn` value depends on how quickly consumers can update their
keys:

- **Leaked key response** — set `expiresOn` to a past date or within minutes.
  Security incidents demand immediate action; a brief disruption is preferable
  to continued exposure.
- **Routine rotation** — 24 to 72 hours gives most teams enough time to
  propagate the new key through CI/CD pipelines, environment variables, and
  secret managers.
- **Scheduled rotation** — for large organizations, 7 to 14 days accommodates
  deploy freezes, multi-team coordination, and staged rollouts.

:::tip{title="Multiple keys per consumer"}

Consumers can also manage rotation themselves by creating a second key,
deploying it, verifying traffic, and then deleting the old key on their own
schedule. This pattern avoids any expiration deadline and puts the consumer in
full control.

:::

:::tip{title="Tags for Request Authorization"}

Most API requests support `tags` as query parameters, even on non-GET requests.
This lets you enforce conditions without a separate lookup. In the example
below, the `orgId` tag ensures the consumer being updated belongs to that
organization.

:::

The following call sets all existing keys to expire on the specified date and
creates a new key without an expiration.

```shell
export ORG_ID=1234
export CONSUMER_NAME=my-consumer
curl \
  https://dev.zuplo.com/v1/accounts/$ACCOUNT_NAME/key-buckets/$BUCKET_NAME/consumers/$CONSUMER_NAME/roll-key?tag.orgId=$ORG_ID \
  --request POST \
  --header "Authorization: Bearer $API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"expiresOn":"2026-04-19T00:00:00.000Z"}'
```

## Reference

The full API Reference for the API Service is hosted using a Zuplo developer
portal at [https://dev.zuplo.com/docs/](https://dev.zuplo.com/docs/).
