# Authentication

> Secret keys (ibe_live_) for servers, publishable keys (ibe_pub_) for browsers, key rotation, and automatic revocation of keys leaked on GitHub.

Source: https://isbusinessemail.com/docs/authentication

Every request except [test addresses](https://isbusinessemail.com/docs/test-addresses) and `GET /v1/health` needs an API key. There are two kinds.

| | Secret key | Publishable key |
|---|---|---|
| Prefix | `ibe_live_…` | `ibe_pub_…` |
| Where it lives | Your server, secret manager, CI secrets | Your web page's JavaScript |
| Endpoints | All `/v1/*` | `/v1/check` only |
| Response | Full response | Reduced response |
| Origin check | None | Must match an allowed origin |
| Limits | Your account tier ([Rate limits](https://isbusinessemail.com/docs/rate-limits)) | Low, separate limits |

## Sending the key

Use either header. Both behave identically.

```bash
# Preferred
curl -s https://api.isbusinessemail.com/v1/check \
  -H "Authorization: Bearer ibe_live_…" \
  -H "Content-Type: application/json" \
  -d '{"domain":"acme.io"}'

# Alternative
curl -s https://api.isbusinessemail.com/v1/check \
  -H "X-API-Key: ibe_live_…" \
  -H "Content-Type: application/json" \
  -d '{"domain":"acme.io"}'
```

Never put a key in a query string.

## Secret keys

- Created in the dashboard under **Keys**. Your first key is created automatically at first sign-in.
- Shown **once**. We store only a SHA-256 hash, so we can't show it again. Lost it? Create a new one and revoke the old one.
- Up to **5 keys** per account. Use one per environment or service, so you can revoke one without touching the others.
- Each key carries a checksum. Mistyped or truncated keys are rejected immediately with `invalid_key`, without a database lookup.
- Revocation takes effect within **60 seconds** everywhere.

## Publishable keys

Publishable keys let a signup form show an inline hint ("Please use your work email") before the user submits. They are designed to be visible in page source, so they are restricted:

- They only work when the request's `Origin` matches one of the **allowed origins** you set on the key (for example `https://app.example.com`). Anything else gets `403 forbidden_origin`.
- They get a **reduced response**: `category`, `is_business`, `recommendation`, `confidence`, `did_you_mean`, `shared_inbox`, `group`, the top reasons and whether Google Workspace / Microsoft 365 was detected (`workspace.microsoft_365_mail` says whether Microsoft runs the email or the domain only has a Microsoft tenant). No `is_blocked`, no deep enrichment, no detailed `mail` or `workspace` blocks.
- They have **low limits** of their own and cannot call batch, feedback or usage.

An `Origin` header can be forged outside a browser, so treat a publishable key as a UX helper. **Always enforce the decision on your server** with a secret key. The [signup form guide](https://isbusinessemail.com/docs/signup-form-guide) shows the full pattern.

## Rotating a key

1. Create a new key in the dashboard.
2. Deploy it to your service (both keys work at the same time).
3. Confirm traffic on the new key in **Usage**.
4. Revoke the old key. It stops working within 60 seconds.

Rotate whenever someone with access leaves, after an incident, or on a schedule that suits you. Key creation and revocation trigger a notification email; the key itself is never in the email.

## Leaked keys are revoked automatically

Secret keys have a recognizable `ibe_live_` prefix and checksum, and we take part in **GitHub secret scanning**. If one of your secret keys is pushed to a public GitHub repository, GitHub reports it to us, we **revoke it automatically** and email you with steps to rotate. Create a new key, deploy it, and remove the old one from your git history.

Avoid leaks in the first place: keep keys in environment variables or a secret manager, add `.env` to `.gitignore`, and never ship a secret key to a browser or mobile app.

## Terms acceptance

API keys belong to an account that has accepted the current [Terms](https://isbusinessemail.com/terms) and [Privacy Policy](https://isbusinessemail.com/privacy). When those change materially, we email you 30 days ahead. During that grace period responses carry a `Warning` header; after it, requests return `403 terms_not_accepted` until someone on the account signs in and accepts.

## Errors you may see

| Code | Status | Meaning |
|---|---|---|
| `unauthorized` | 401 | No key sent (and the input isn't a test address) |
| `invalid_key` | 401 | Malformed key or unknown key |
| `key_revoked` | 401 | The key was revoked (by you, an admin, or leak detection) |
| `forbidden_origin` | 403 | Publishable key used from an origin that isn't allowed |
| `terms_not_accepted` | 403 | The account must accept updated terms |

Full list: [Errors](https://isbusinessemail.com/docs/errors).
