> For the complete documentation index, see [llms.txt](https://boundaryai.gitbook.io/boundaryai-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://boundaryai.gitbook.io/boundaryai-docs/api-and-webhooks/authentication.md).

# Authentication & API keys

API keys, permission scopes, environments, and rate limits.

Every API call authenticates with an **API key** passed as a bearer token:

```
Authorization: Bearer inpk_live_...
```

There are no session cookies on the API: one key, one header. Dashboard features (building surveys, managing members, organisation settings) are not reachable with an API key by design. The one place sign-in based access exists is the AI-assistant connection flow, which uses OAuth instead of a key; see [Connect AI assistants](/boundaryai-docs/api-and-webhooks/mcp.md).

***

### Creating and managing keys

Keys live in the dashboard under **Integrations → Developer tools → API Keys** (admin-only). Each key has:

* A **label**, so you can tell your CRM sync from your data-warehouse export.
* An **environment**: `inpk_live_*` for production traffic, `inpk_test_*` for staging integrations. They behave identically; the split exists so you can revoke staging without touching production. Test keys are never charged usage.
* A **permission scope** (below).
* A **per-key rate limit**, 60 requests/minute by default, adjustable between 1 and 300 at creation or later.
* **Per-key usage statistics**, including real response status codes, so you can spot a failing integration from the dashboard.

The secret is shown **once** at creation. Store it like a password; rotate it from the same screen if it leaks or when a teammate with access leaves.

***

### Permission scopes

Scope what each integration can do; don't hand every system an `all` key.

| Scope      | What it allows                                                                                                                                                                     |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `push`     | Push feedback to existing sources, and everything push implies: bulk status, file upload, feedback listing and erasure, analysis reads.                                            |
| `create`   | Everything `push` can, plus creating and publishing sources with their fields inside existing feedback groups.                                                                     |
| `send`     | Trigger survey-invite emails ([Sending invites](/boundaryai-docs/api-and-webhooks/sending-invites.md)). Deliberately separate: emailing humans is a bigger deal than pushing data. |
| `mcp_read` | Read-only access for the MCP endpoint, so an AI assistant can query analytics but never write. See [Connect AI assistants](/boundaryai-docs/api-and-webhooks/mcp.md).              |
| `all`      | Everything above, plus creating feedback groups (`POST /feedback_groups/create`), which no narrower scope can do.                                                                  |

Every write operation in the API reference states the scope it requires. A call outside the key's scope returns **403** with the code `INSUFFICIENT_PERMISSION`.

{% hint style="info" %}
`send` is additionally gated on a **verified sending domain**: API sends never ride the shared BAI Analytics sender, so automated volume runs on your own sending reputation. See [Sending invites](/boundaryai-docs/bringing-in-your-feedback/surveys/managing-surveys.md#sending-invites).
{% endhint %}

{% hint style="info" %}
`mcp_read` keys are **bound to the person who created them**. On every MCP request the platform re-checks that this person still has an active account and is still a member of the organisation; if not, the key stops working immediately (403 `MCP_KEY_UNBOUND`) and shows as stopped in the dashboard. Integration keys (`push`, `create`, `send`, `all`) are organisation keys and outlive their creator, so an ETL pipeline keeps running after the engineer who set it up leaves.
{% endhint %}

***

### Introspection: `GET /me`

An integration can discover its own capabilities without dashboard access:

```bash
curl https://boundaryai-ingest-279197672085.europe-west9.run.app/api/input/me \
  -H "Authorization: Bearer $BAI_API_KEY"
```

The response includes the key's name, environment, and permissions, the organisation's id and `org_name` (handy as the label of a stored connection), the **effective rate limits**, the organisation's usage status under `credits`, and the **webhook event types** available for subscription. It charges nothing, which also makes it the right target for connection tests.

***

### Rate limits

Defaults: **60 requests/minute per key**, **300 requests/minute per organisation**, and 600 per minute per IP address. Windows are fixed 60-second windows anchored at the first request: a request rejected with 429 does not extend the wait, so `Retry-After` is exact. Your key's numbers are in `GET /me`; the per-key limit can be raised up to 300 when the key is created or edited.

When you hit a limit the API returns **429** with a `Retry-After` header, and every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. Back off and retry; for sustained volume, prefer the bulk endpoints (one call for thousands of items) over per-item calls.

***

### Response envelope

Today, 2xx responses carry the payload directly, as shown in every example of the reference, together with `Deprecation` and `Sunset` headers. Those headers announce one thing only: after the sunset date, success payloads will be wrapped as `{"data": {...}}`, as the schemas already declare. No endpoint is being deprecated. Errors are always `{"error": {"code": "...", "message": "..."}}` with an optional `details` object.

***

### Good practices

* **One key per integration.** Revoking a compromised system shouldn't take down the others.
* **Scope down.** A CRM sync needs `push`, not `all`.
* **Use `Idempotency-Key` on writes.** Any push can be retried safely within 24 hours.
* **Rotate on staff changes.** Same policy as passwords.
