# API keys

> Create as many SerpKite API keys as you need, give each a monthly credit limit, and rotate or revoke them without downtime. Keys are stored as hashes and shown only once.

## Keys at a glance

- **Format:** `skt_live_` plus a random secret. The dashboard shows a short prefix such as `skt_live_Ab12` so you can tell keys apart.
- **Shown once:** the full secret appears only when the key is created or rotated. SerpKite stores a SHA-256 hash, never the key itself.
- **Many per account:** one per service or environment is a good default.
- **Account-wide balance:** all keys spend from the same credit balance. A [per-key monthly limit](#per-key-monthly-limit) caps how much of it a single key can use.
- **Same rate per key:** each key gets the account's [rate limit](https://serpkite.com/docs/rate-limits) on its own.

Manage keys in the dashboard at [app.serpkite.com](https://app.serpkite.com) under **API keys**. On a [team](https://serpkite.com/docs/team), every member can see and manage the account's keys, and each key records who created it.

## Create a key

1. ### Open API keys

   In the dashboard, open **API keys** and click **Create key**.

2. ### Name it and, optionally, limit it

   Give the key a name of up to 64 characters that says where it's used, such as `prod-agent` or `n8n`. Optionally set a monthly credit limit.

3. ### Copy the secret

   Copy the secret into your secrets manager or environment (`SERPKITE_API_KEY`). Once you close the dialog it can't be shown again.

## Per-key monthly limit

A key can have a **monthly credit limit**. It counts the credits that key spends in the current UTC calendar month and resets at 00:00 UTC on the first of the month.

When a call would push the key past its limit, it is rejected before running with `403 key_limit_reached` and is not billed:

```json
{
  "error": {
    "code": "key_limit_reached",
    "message": "this key's monthly credit limit is reached",
    "request_id": "req_01J8ZKC4T9HV2"
  }
}
```

Other keys keep working. Raise the limit, clear it (no limit) or wait for the next month. The key list shows each key's usage this month next to its limit, and [`GET /v1/account`](https://serpkite.com/docs/endpoints/account) returns the calling key's `credit_limit` and `credits_used_month`, so a service can check its own headroom:

cURL:

```bash
curl "https://api.serpkite.com/v1/account" \
  -H "Authorization: Bearer $SERPKITE_API_KEY"
```

TypeScript:

```ts
import { SerpKite } from "serpkite";

const sk = new SerpKite();
const account = await sk.account();
console.log(account.balance, account.month.credits);
```

Python:

```python
from serpkite import SerpKite

sk = SerpKite()
account = sk.account()
print(account.balance, account.month.credits)
```

Go:

```go
c := serpkite.NewClient()
account, err := c.Account(ctx)
if err != nil {
	log.Fatal(err)
}
fmt.Println(account.Balance, account.Month.Credits)
```

```json
{
  "balance": 61499.5,
  "rate_limit_rps": 50,
  "plan": "paid",
  "key": { "id": "0192f7a4-…", "name": "prod-agent", "credit_limit": 20000, "credits_used_month": 3120.5 },
  "monthly_spend_cap": 50000,
  "month": { "credits": 4210.5, "requests": 4388 }
}
```

Per-key limits are separate from the account-wide [monthly spend cap](https://serpkite.com/docs/spend-controls#monthly-spend-cap). Both apply; whichever is hit first stops the call.

Good uses for key limits:

- Give each customer, tenant or agent its own key with a budget.
- Give a staging or CI key a small limit so a runaway test can't drain the balance.
- Hand a contractor or a no-code tool a key with a hard ceiling.

### Limits on a team

Only the account owner sets or changes key limits. On a [team](https://serpkite.com/docs/team), the owner can set a **member key limit**: every key a member creates gets that monthly limit automatically, and the member can't raise, lower or remove it. Members can still rename, rotate and revoke the keys they created; the limit stays as it is. Without a member key limit, keys members create have no limit. See [Team](https://serpkite.com/docs/team#member-key-limit).

## Engine fallback

Each key has a switch, **Allow fallback to other search engines**, which is off by default. With it on, requests from that key that don't send an `engine` parameter behave as `engine=auto`: when Google is unavailable they may be answered by Brave, Bing and others, and `meta.engine` names the engine that answered. Requests that name an `engine` are unaffected. Toggle it in the key list, or from the key's **Edit** dialog. See [Search providers](https://serpkite.com/docs/providers).

## Rotate a key

Rotating replaces the key's secret in place: the old secret stops working and the key keeps its **id, name, monthly limit and this month's usage**, so a key that reached its limit stays at it. The new secret is shown once.

To rotate without downtime when a key hasn't leaked, create a second key, deploy it, then revoke the first. Use **Rotate** when you need the old key dead now, for example after it was committed to a repository.

## Revoke a key

**Revoke** (delete) makes the key stop working. Requests with it get `401 unauthorized`. Revocation takes effect immediately in most cases and within a minute at most, since validated keys are cached briefly. Revoked keys disappear from the list; their past usage stays in your usage history.

## Key activity

For each key the dashboard shows when it was created, who created it, when it was last used (updated at most once a minute), and credits used this month. **Usage** breaks down requests and credits per key, and the request log can be filtered by key. The log stores metadata only, never query text. See [Privacy and data retention](https://serpkite.com/docs/privacy-and-data-retention).

## Managing keys from code

The dashboard is backed by an API at `app-api.serpkite.com`, authenticated with the dashboard session cookie rather than an API key. It isn't a public, versioned API yet, but for reference these are the key operations it exposes:

| Operation | Request |
| --- | --- |
| List keys | `GET /v1/keys` |
| Create | `POST /v1/keys` with `{"name": "…", "credit_limit": 20000}` |
| Rename or change the limit | `PATCH /v1/keys/{id}` (omit `credit_limit` to keep it; `"credit_limit": null` clears it; owner only) |
| Turn engine fallback on or off | `PATCH /v1/keys/{id}` with `{"allow_fallback": true}` |
| Rotate | `POST /v1/keys/{id}/rotate` |
| Revoke | `DELETE /v1/keys/{id}` |

## Related

- [Authentication](https://serpkite.com/docs/authentication): How to send a key, and how to keep it secret.
- [Spend controls](https://serpkite.com/docs/spend-controls): Account-wide cap, alerts and auto-recharge.
- [Team](https://serpkite.com/docs/team): Share keys and balance with teammates.
- [GET /v1/account](https://serpkite.com/docs/endpoints/account): Check balance and key limit from code.