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

# Authentication

> API keys, Bearer tokens, and OAuth scopes for the Sight AI Developer Platform

## REST API (API keys + OAuth)

The v1 REST API accepts two credential types:

* **API keys** (`sai_<64hex>`) — server-to-server. Create them in **Integrations → Sight AI API**. Shown once at creation.
* **OAuth access tokens** (`sai_oauth_*`) — for app integrations that completed the OAuth consent flow. See [MCP Setup](/developers/mcp-setup) and [Webhooks](/developers/webhooks) for the OAuth flow.

```bash theme={null}
curl -s https://app.trysight.ai/api/v1/sites \
  -H "Authorization: Bearer sai_YOUR_KEY_OR_TOKEN"
```

### Key format (API keys)

* Prefix: `sai_`
* 64 hex characters after the prefix
* Team-scoped; optional site restrictions at creation time

### OAuth (app integrations)

App integrations use OAuth 2.1 Authorization Code + PKCE. Register an OAuth client in **Integrations → Sight AI API → OAuth apps**, redirect users to `/oauth/authorize`, exchange the code at `/oauth/token`. The resulting `sai_oauth_*` access token works on both `/api/v1/*` and `/mcp`. See [Webhooks](/developers/webhooks#the-oauth-flow) for an end-to-end example.

PKCE (`S256`) is **required for every client**, including server-side ones.

#### Public vs. confidential clients

When registering an OAuth app you choose how the client authenticates at the token endpoint:

| Type         | `token_endpoint_auth_method`                  | Use it when                                                                                 | Secret?                   |
| ------------ | --------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------- |
| Public       | `none`                                        | Desktop MCP clients (Cursor, Claude), SPAs, mobile apps — anything that can't keep a secret | No — PKCE only            |
| Confidential | `client_secret_basic` or `client_secret_post` | A server-side app (CRM, helpdesk, sales tool) with a backend that can store a secret        | Yes — secret **and** PKCE |

Confidential clients are created only by an authenticated team admin in the dashboard, which returns the `client_secret` (`sai_ocsec_…`) **once**. Store it server-side; it cannot be retrieved later. At the token endpoint, present it alongside PKCE:

* `client_secret_basic` — `Authorization: Basic base64(client_id:client_secret)`
* `client_secret_post` — `client_id` and `client_secret` in the request body

```bash theme={null}
# Confidential client, client_secret_post
curl -s -X POST https://app.trysight.ai/oauth/token \
  -d grant_type=authorization_code \
  -d code=AUTH_CODE \
  -d redirect_uri=https://your.app/callback \
  -d client_id=sightai_YOUR_CLIENT_ID \
  -d client_secret=sai_ocsec_YOUR_SECRET \
  -d code_verifier=PKCE_VERIFIER
```

For a stolen refresh token to be redeemed, an attacker would need both the `client_secret` **and** a valid PKCE exchange — so confidential clients add defense-in-depth on top of PKCE. Use a public client only when the integrator genuinely can't hold a secret.

#### Rotating a client secret

If a `client_secret` is exposed (or just on a schedule), rotate it from **Integrations → Sight AI API → OAuth apps**:

1. Find the confidential client and click **Rotate secret**.
2. Confirm — the old secret stops working immediately. The new secret is shown **once**; store it server-side.
3. Update your integration with the new secret.

Rotation generates a new secret and stores only its SHA-256 hash, so it can never be retrieved after this one-time display. Outstanding access tokens remain valid until their natural expiry (\~1 hour); outstanding refresh tokens can no longer be redeemed without the new secret, so anyone holding the old secret is cut off from refreshing. To fully invalidate every issued token, revoke the client instead.

Only confidential clients have a secret to rotate — public clients use PKCE alone.

### Scopes

| Scope                | Access                                                                                                                            |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `analytics:read`     | Search + AI visibility analytics                                                                                                  |
| `opportunities:read` | AI + search content opportunities                                                                                                 |
| `articles:read`      | List/get articles, limits                                                                                                         |
| `articles:write`     | Create, edit, SEO refresh                                                                                                         |
| `agents:read`        | Agent configs and runs                                                                                                            |
| `agents:write`       | Toggle agents, trigger runs                                                                                                       |
| `inbox:read`         | Read Outreach Agent inbox conversations and messages (contains contact PII)                                                       |
| `inbox:write`        | Reply to inbox threads, update conversation status, take over for the agent, mark as read, and ingest forwarded outreach messages |
| `webhooks:read`      | List outreach webhook subscriptions                                                                                               |
| `webhooks:write`     | Create, update, and delete outreach webhook subscriptions                                                                         |

### Idempotency-Key

The `POST /api/v1/sites/{siteId}/outreach/inbox/messages` endpoint accepts an optional `Idempotency-Key` header. When supplied, a repeat request with the same key replays the cached response (HTTP 200) instead of re-running the ingestion pipeline — so you can safely retry a failed or timed-out request without creating duplicate conversations.

* Any opaque string up to 128 characters (alphanumeric, `.`, `_`, `-`, `:`).
* Scoped to your API key — two different keys can reuse the same value.
* Cached for 24 hours; after that the same key is treated as a fresh ingestion.

See [Outreach Inbox](/developers/api-reference/outreach-inbox#idempotency) for details.

## MCP (OAuth only)

MCP clients **must not** use API keys. Use OAuth 2.1 Authorization Code + PKCE.

* Authorization: `GET /oauth/authorize`
* Token: `POST /oauth/token`
* Metadata: `GET /.well-known/oauth-authorization-server`

Only team **owners and admins** can authorize MCP clients.

## Errors

| Status | Meaning                               |
| ------ | ------------------------------------- |
| 401    | Missing or invalid credentials        |
| 403    | Insufficient scope or unlicensed site |
| 429    | Rate limit exceeded                   |
