> For the complete documentation index, see [llms.txt](https://docs.limecall.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.limecall.com/developers/api-keys.md).

# API keys

Create, scope and revoke API tokens — and the 14 scopes the API actually enforces.

Open **Settings → API keys**, or the **Developers** page.

## Creating a key

1. Open **Settings → API keys**.
2. Create a key and give it a name.
3. Choose its scopes.
4. Copy the token.

{% hint style="warning" %}
The token is shown once, at creation. It cannot be retrieved afterwards. Store it in your secret manager immediately — if you lose it, revoke it and create another.
{% endhint %}

## Naming

Name keys for where they are used: `zapier-production`, `billing-sync`, `marketing-site`.

A list of keys called "API key 1" through "API key 6" cannot be audited, and nobody will dare revoke any of them.

## Scopes

The dashboard offers two broad choices when you create a key — **Read** and **Write**. The API itself enforces finer-grained scopes, one pair per resource:

| Resource      | Read                 | Write                 |
| ------------- | -------------------- | --------------------- |
| Calls         | `calls:read`         | `calls:write`         |
| Messages      | `messages:read`      | `messages:write`      |
| Contacts      | `contacts:read`      | `contacts:write`      |
| Phone numbers | `phone-numbers:read` | `phone-numbers:write` |
| Users         | `users:read`         | `users:write`         |
| Webhooks      | `webhooks:read`      | `webhooks:write`      |
| Analytics     | `analytics:read`     | —                     |
| Devices       | —                    | `devices:write`       |

Wildcards work: `calls:*` satisfies both `calls:read` and `calls:write`.

Grant the narrowest set that does the job. A reporting dashboard needs `calls:read` and `analytics:read` — not permission to send messages or delete contacts.

A request whose key lacks the required scope returns `403` with the scope it wanted:

```json
{ "error": "Forbidden", "message": "Insufficient permissions. Required scope: calls:write" }
```

That message names exactly what to add, which makes a `403` quick to fix.

## Using a key

```bash
curl https://app.limecall.com/api/v1/calls \
  -H "Authorization: Bearer sk_live_..."
```

The prefix matters. `sk_live_` is the secret API key. A `pk_live_` or `lk_live_` value is the **widget publishable key** — a different credential entirely, and it is rejected at format check before any lookup.

## Keeping keys safe

**Never commit a key to a repository.** Use environment variables or a secret manager. Keys committed to public repositories are found by automated scanners within minutes.

**Never put a key in front-end code.** Anything in a browser is visible to anyone who opens developer tools. If a browser needs data, proxy through your own backend.

**Use separate keys per integration.** Then revoking one does not break the others, and you can tell what a leak touched.

**Rotate periodically.** Create the new key, deploy it, confirm it works, then revoke the old one — in that order, so there is no gap.

{% hint style="warning" %}
A key is organization-wide and carries no IP restriction. Anywhere it leaks, it works. That is the whole reason to scope keys narrowly and rotate them.
{% endhint %}

## Revoking

Revoke a key from the same page. It stops working immediately and anything using it fails.

Revoke at once if a key may have been exposed — committed, pasted into a ticket, or held by someone who has left.

## When someone leaves

Check for keys they created. Keys are not tied to a person's session and keep working after their account is deactivated. See [Team & roles](/account/team-and-roles.md).

## Live keys only

`sk_live_` keys act on your real account — real calls, real messages, real charges. There is no sandbox that makes a mistake free, so test destructive operations against data you do not mind changing.
