> ## 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](https://docs.trysight.ai/developers/mcp-setup.md) and [Webhooks](https://docs.trysight.ai/developers/webhooks.md) for the OAuth flow.

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

### 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](https://docs.trysight.ai/developers/webhooks.md#the-oauth-flow) for an end-to-end example.

A newly registered app starts **in development**: only owners and admins of the team that registered it can authorize it. Submit it for review from the OAuth apps page to let any Sight AI customer connect. See [OAuth apps](https://docs.trysight.ai/developers/oauth-apps.md) for the lifecycle and what the review checks.

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, and every SEO module read |
| `seo:write` | Run SEO checks and paid lookups (rank checks, audits, keyword research, domain explore) and manage SEO keywords, competitors, alert rules, annotations, reports and settings |
| `opportunities:read` | AI + search content opportunities |
| `articles:read` | List/get articles, limits |
| `articles:write` | Create, edit, SEO refresh |
| `keywords:read` | List keywords, inspect pipeline status, and read keyword-to-article linkage |
| `keywords:write` | Add keywords individually or in bulk for article generation |
| `integrations:read` | Read CMS connections, active integration, and article sync status |
| `integrations:write` | Sync articles to the connected CMS integration |
| `planner:read` | Read planner settings and scheduled CMS publish queue |
| `planner:write` | Schedule articles and manage planner settings |
| `indexing:read` | Read GSC/IndexNow status, submission history, and account setup health |
| `indexing:write` | Submit sitemaps to Google Search Console and article URLs to IndexNow |
| `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](https://docs.trysight.ai/developers/api-reference/outreach-inbox.md#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 |


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