> ## Documentation Index
> Fetch the complete documentation index at: https://unkey.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Usage Limits (Credits)

> Set usage limits on API keys to cap the total number of requests. Unkey automatically enforces credit-based quotas and blocks excess usage.

Usage limits let you set a maximum number of requests a key can make. After the limit is reached, the key becomes invalid until you add more credits or reset it. This is different from rate limiting, which controls *frequency*, usage limits control *total volume*.

## When to use this

<CardGroup cols={2}>
  <Card title="Pay-per-use APIs" icon="coins">
    Sell API credits that get consumed with each request. Customer buys 10,000
    requests, key stops working at 10,001.
  </Card>

  <Card title="Trial/freemium tiers" icon="flask">
    Give new users 100 free requests to try your API. They upgrade or stop.
  </Card>

  <Card title="Subscription quotas" icon="calendar">
    "Pro plan includes 50,000 requests/month", combine with
    [auto-refill](/platform/apis/features/refill) for recurring limits.
  </Card>

  <Card title="One-time tokens" icon="ticket">
    Create a key that works exactly once, like a single-use download link.
  </Card>
</CardGroup>

## How it works

1. Create a key with `credits.remaining` set to your limit
2. Each verification decrements the remaining count
3. When remaining hits 0, verification fails with `code: USAGE_EXCEEDED`
4. You can add more credits anytime via the API

## Create a key with usage limits

<CodeGroup>
  ```bash cURL theme={"theme":"kanagawa-wave"}
  curl -X POST https://api.unkey.com/v2/keys.createKey \
    -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "apiId": "api_...",
      "credits": {
        "remaining": 1000
      }
    }'
  ```

  ```typescript TypeScript theme={"theme":"kanagawa-wave"}
  import { Unkey } from "@unkey/api";

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

  try {
    const { meta, data } = await unkey.keys.createKey({
      apiId: "api_...",
      credits: {
        remaining: 1000,
      },
    });

    console.log(data.keyId); // Give this key to your user
  } catch (err) {
    console.error(err);
    return Response.json({ error: "Internal error" }, { status: 500 });
  }
  ```
</CodeGroup>

## Verification response

When you verify a key with usage limits, the response includes the current credit count:

```json theme={"theme":"kanagawa-wave"}
{
  "meta": { "requestId": "req_..." },
  "data": {
    "valid": true,
    "code": "VALID",
    "keyId": "key_...",
    "credits": 999
  }
}
```

<Note>
  The `credits` value shows remaining credits **after** this verification. A
  value of `999` means the key can be verified 999 more times.
</Note>

When credits are exhausted:

```json theme={"theme":"kanagawa-wave"}
{
  "meta": { "requestId": "req_..." },
  "data": {
    "valid": false,
    "code": "USAGE_EXCEEDED",
    "keyId": "key_...",
    "credits": 0
  }
}
```

## Custom cost per request

By default, each verification costs 1 credit. But some operations should cost more, maybe a complex query costs 10 credits while a simple lookup costs 1.

Specify the cost at verification time:

<CodeGroup>
  ```bash cURL theme={"theme":"kanagawa-wave"}
  curl -X POST https://api.unkey.com/v2/keys.verifyKey \
    -H "Content-Type: application/json" \
    -d '{
      "key": "sk_...",
      "credits": {
        "cost": 10
      }
    }'
  ```

  ```typescript TypeScript theme={"theme":"kanagawa-wave"}
  try {
    const { data } = await unkey.keys.verifyKey({
      key: "sk_...",
      credits: { cost: 10 }, // Deduct 10 credits for this request
    });

    if (!data.valid) {
      return Response.json({ error: data.code }, { status: 401 });
    }
  } catch (err) {
    console.error(err);
    return Response.json({ error: "Internal error" }, { status: 500 });
  }
  ```
</CodeGroup>

<Warning>
  If the key doesn't have enough remaining credits, the verification fails. A
  key with 5 remaining credits will reject a request with `cost: 10`.
</Warning>

### Cost of 0 (check without consuming)

Set `cost: 0` to verify a key without consuming any credits. Useful for checking key validity or metadata without affecting the balance.

```json theme={"theme":"kanagawa-wave"}
{
  "key": "sk_...",
  "credits": { "cost": 0 }
}
```

## Add more credits

When a user purchases more credits or you need to refill manually:

<CodeGroup>
  ```bash cURL theme={"theme":"kanagawa-wave"}
  curl -X POST https://api.unkey.com/v2/keys.updateCredits \
    -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "keyId": "key_...",
      "operation": "increment",
      "value": 5000
    }'
  ```

  ```typescript TypeScript theme={"theme":"kanagawa-wave"}
  try {
    const { meta, data } = await unkey.keys.updateCredits({
      keyId: "key_...",
      operation: "increment",
      value: 5000,
    });
  } catch (err) {
    console.error(err);
    return Response.json({ error: "Internal error" }, { status: 500 });
  }
  ```
</CodeGroup>

Operations available:

* `set`, Set credits to an exact value
* `increment`, Add credits to current balance
* `decrement`, Subtract credits from current balance

## Remove usage limits

To make a key unlimited again, set credits to `null`:

```bash theme={"theme":"kanagawa-wave"}
curl -X POST https://api.unkey.com/v2/keys.updateKey \
  -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "keyId": "key_...",
    "credits": null
  }'
```

## Usage limits vs rate limits

| Feature               | Usage Limits             | Rate Limits                  |
| --------------------- | ------------------------ | ---------------------------- |
| What it controls      | Total requests ever      | Requests per time window     |
| Resets automatically? | No (unless using refill) | Yes, after window expires    |
| Use case              | Billing, quotas, trials  | Abuse protection, fair usage |
| Example               | "1000 requests total"    | "100 requests per minute"    |

**Use both together:** Rate limits protect against burst abuse, usage limits enforce billing quotas.

## Next steps

<CardGroup cols={2}>
  <Card title="Auto-refill" icon="arrows-rotate" href="/platform/apis/features/refill">
    Automatically reset credits on a schedule (daily, monthly)
  </Card>

  <Card title="Rate limiting" icon="gauge-high" href="/platform/apis/features/ratelimiting/overview">
    Control request frequency, not just total volume
  </Card>
</CardGroup>
