Skip to main content
API keys are the most common way to authenticate requests to your API. Unkey handles the entire lifecycle — creating keys, verifying them on every request, tracking usage, and revoking them when needed — so you can focus on your actual API logic.

When to use API keys

API keys work best when you need:
  • Machine-to-machine authentication — Backend services, scripts, or integrations calling your API
  • Usage tracking per customer — Know who’s making requests and how many
  • Simple integration — A single header (Authorization: Bearer sk_...) that developers understand
  • Granular control — Per-key rate limits, expiration, and permissions
For user-facing authentication (login flows, sessions), you’ll typically use OAuth, JWTs, or an auth provider like Clerk or Auth0 alongside Unkey. Unkey handles the API key layer, not user sessions.

How it works

1

Create an API in Unkey

An “API” in Unkey is a container for keys. You might have separate APIs for “Production” and “Staging”, or for different products.
2

Issue keys to users

When a user signs up or requests API access, create a key for them. You can attach metadata (user ID, plan tier), set limits, and configure expiration.
3

Verify on every request

When a request hits your API, extract the key from the header and verify it with Unkey. We’ll tell you if it’s valid, who it belongs to, and how many requests they have left.
4

Manage the lifecycle

Revoke keys when users churn. Rotate keys when security requires it. Update limits when users upgrade. All through the dashboard or API.

Quick example

Here’s what verification looks like in practice:
import { Unkey } from "@unkey/api";

const unkey = new Unkey({ rootKey: process.env.UNKEY_ROOT_KEY! });

export async function handler(req: Request) {
  // 1. Extract the key from the Authorization header
  const key = req.headers.get("Authorization")?.replace("Bearer ", "");

  if (!key) {
    return new Response("Missing API key", { status: 401 });
  }

  try {
    // 2. Verify with Unkey
    const { meta, data } = await unkey.keys.verifyKey({ key });

    if (!data.valid) {
      // Key is invalid, expired, rate limited, or has no remaining uses
      return new Response("Unauthorized", { status: 401 });
    }
    // Continue with your API logic...
    return new Response("Hello!");
  } catch (err) {
    console.error(err);
    return new Response("Service unavailable", { status: 503 });
  }
}

What you get with each verification

When you verify a key, Unkey returns:
FieldTypeDescription
validbooleanWhether the key passed all checks
codestringStatus code (VALID, NOT_FOUND, RATE_LIMITED, etc.)
keyIdstringThe key’s unique identifier
namestring?Human-readable name of the key
metaobject?Custom metadata associated with the key
expiresnumber?Unix timestamp (in milliseconds) when the key will expire. (if set)
creditsnumber?Remaining uses (if usage limits set)
enabledbooleanWhether the key is enabled
rolesstring[]?Permissions attached to the key
permissionsstring[]?Permissions attached to the key
identityobject?Identity info if externalId was set when creating the key
ratelimitsobject[]?Rate limit states (if rate limiting configured)

Features

Unkey keys support much more than basic authentication:

Next steps

Last modified on February 14, 2026