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

# Authentication

> How to create, use, and rotate Sendora API keys.

## API keys

All Sendora API requests authenticate with an API key passed in the `X-API-Key` request header.

```bash theme={"dark"}
curl https://api.sendora.ai/api/v1/public/leads \
  -H "X-API-Key: sk_live_..."
```

### Key formats

| Prefix | Environment | Notes |
| - | - | - |
| `sk_live_` | Production | Hits real data, triggers real sends |
| `sk_test_` | Test-prefixed key | Do not assume isolation from real data, sends, calls, or charges |

Use a deliberately limited workspace and non-destructive requests for development. A test-prefixed key is not a substitute for a separately isolated sandbox.

## Creating a key

1. Log in to [app.sendora.ai](https://app.sendora.ai)
2. Go to **Settings → API Keys**
3. Click **Generate new key**
4. Give it a descriptive label (e.g., `zapier-integration`, `n8n-production`)
5. Copy it immediately, it is **shown only once**

Each key records the workspace role of the person who created it and shows it in the key list; keys created earlier show no creator and work exactly as before. Only managers, admins and owners can create API keys, and every request is checked against the creator's current role.

<Warning>
  Store API keys in environment variables or a secrets manager. Never hardcode them in source code or commit them to git.
</Warning>

## Rotating a key

1. Generate a new key
2. Update your integration to use the new key
3. Delete the old key from **Settings → API Keys**

There is no forced rotation schedule, but rotating keys every 90 days is recommended.

## Permissions, scopes, role and plan

A key authenticates one workspace. What it may do is the combination of four checks, applied on every request:

| Check | What it does | Failure |
| - | - | - |
| Key state | The key must exist, be active, not revoked and not expired. | `401` |
| Scope | `GET`, `HEAD` and `OPTIONS` need the `read` scope. Every other method needs `write`. `write` does not imply `read`, so give a key both when it must read and write. `all` (and the older `*`) grant both. A key created before scopes existed has no scope list and keeps read and write. | `403` |
| Workspace boundary | A key only ever sees its own workspace. An ID from another workspace is reported as `404`. | `404` |
| Plan entitlement | The workspace plan (or an administrator override) must include public API access. If that cannot be determined the request fails closed. | `403`, or `503` with `Retry-After` |
| Creator's current access | For a key with a recorded creator, that person must still be an active member of the workspace, their current role must include API access (owner, admin or manager), and it must allow the endpoint (phone numbers, connected accounts, webhook endpoints and agency endpoints need admin). Checked on every request. Keys created before creators were recorded skip this check. | `403`, or `503` with `Retry-After` |

Keys are created with `read`, `write`, `all` or `*`. Any other scope is rejected with `422` when the key is created.

<Warning>
  A key follows its creator's current access. If the person who created it is removed or suspended, the key stops working (`403`); if their role is reduced, the key loses whatever the new role cannot do. Keys created before creators were recorded show no creator and act as workspace-level service identities, so delete or replace them when people leave. Issue the narrowest scope that works (`read` for reporting) and keep one key per integration.
</Warning>

## Your Sendora key is not your AI-provider key

There are two separate credentials, and they are never interchangeable:

| Credential | Where you set it | What it does |
| - | - | - |
| **Sendora API key** (`sk_live_...`) | **Settings → API Keys** | Sent in `X-API-Key`. Proves which workspace is calling and what it may do. |
| **AI-provider key** (your own model key, optional) | The workspace's AI settings, or a campaign's AI configuration | Stored encrypted on the server and used only when Sendora runs an AI step for that workspace. |

You never send a provider key to the API, and the API never returns one. Sendora resolves the provider and model for each workspace on the server, from the campaign's own AI configuration first and the workspace default after that. If your own key is missing or fails, AI steps fall back to the platform default and are billed as documented for your plan; the API does not accept a provider key or model credential in a request to override this. Connected AI assistants (the workspace MCP) sign in with OAuth, not with an API key.

## Credits and usage

Requests that run a billable action (AI steps, messages, calls, enrichment) are charged to the workspace that owns the key, using the same rates as the app. A `GET` never spends credits. When a write may be retried, send an `Idempotency-Key` so a retry cannot repeat the action (see [Idempotency](/concepts/idempotency)). The usage shown in the app is the source of truth for what was charged; do not infer charges from an HTTP `200` alone.

## Security checklist

* [ ] Keys stored in environment variables, not source code
* [ ] A deliberately limited workspace is used for non-production testing
* [ ] One key per integration (easier to rotate without affecting others)
* [ ] Old / unused keys deleted from the dashboard
* [ ] Webhook signatures verified on every inbound event (see [Webhooks](/guides/webhooks))

## Error responses

| Status | Meaning |
| - | - |
| `401 Unauthorized` | Missing or invalid `X-API-Key` header |
| `403 Forbidden` | The key lacks the required `read` or `write` scope, the workspace lacks a required entitlement, or a widget origin is not allowed |
| `503 Service Unavailable` | Entitlement or key state could not be checked right now. Retry after the `Retry-After` interval |
| `429 Too Many Requests` | Rate limit hit, back off and retry (see [Rate Limits](/rate-limits)) |

Resource ownership failures are intentionally reported as `404 Not Found` so a
key cannot use the API to discover another workspace's resource IDs. `403` is
reserved for entitlement and widget-origin policy failures.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.