---
title: Authentication
description: How to authenticate API requests with a Bearer key.
---

ZevSend uses Bearer token authentication. Every request must
include a valid API key in the `Authorization` header:

```bash
curl https://api.zevsend.com/v1/emails \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json"
```

## Creating an API key

Open **Settings → API keys** in the dashboard and click
**Create key**. We'll show the secret value once. Copy it
immediately — we never store it in a recoverable form, and
losing it means creating a new key.

```text
sk_test_a1b2c3d4e5f6...   # sandbox traffic
sk_live_a1b2c3d4e5f6...   # live traffic
```

## Test vs live keys

The prefix tells you which mode the key targets:

| Prefix      | Mode    | When you can create one              |
| ----------- | ------- | ------------------------------------ |
| `sk_test_…` | Sandbox | Immediately. Default for new teams.  |
| `sk_live_…` | Live    | After your team is approved.         |

Both types call the same endpoints — the key implies the mode.
You can have both active at the same time so you can run your
staging environment against `sk_test_` and production against
`sk_live_`.

## Per-key domain scope

When you create a key you can pin it to a specific verified
domain. A key pinned to one domain can only send under that
brand identity — useful when a single team owns more than one
brand and you want to limit blast radius if a key leaks.

To send under a different domain on the same team, create a
separate key for that domain.

## Rotating a key

When you suspect a key is compromised:

1. Create a new key in the dashboard.
2. Deploy the new key to your application.
3. Revoke the old key from the dashboard.

Revoking a key takes effect immediately — in-flight requests
on the old key fail with `401 invalid_api_key`. Messages
already accepted are unaffected.

## Authentication errors

| Status | Code                | Meaning                                         |
| ------ | ------------------- | ----------------------------------------------- |
| `401`  | `missing_api_key`   | No `Authorization` header.                      |
| `401`  | `invalid_api_key`   | The key isn't valid or has been revoked.         |
| `401`  | `api_key_revoked`   | The key was revoked from the dashboard.         |
| `403`  | `key_domain_scope`  | The key is pinned to a different domain.        |

## Safe key handling

- **Never commit keys to source control.** Use environment
  variables or a secret store.
- **Never embed live keys in mobile or browser apps.** The
  client side is not a safe place for a server credential.
  Proxy through a backend you control.
- **Use the principle of least privilege.** Create separate
  keys for separate services so a leak from one doesn't
  compromise the rest.