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

# Authentication

> How to authenticate requests using API keys or OAuth 2.1 access tokens.

Every request to the SocialAPI `/v1` endpoints requires a Bearer token in the `Authorization` header. The API accepts two token types.

## Token types

| Token type                 | Who uses it                           | Format                                     |
| -------------------------- | ------------------------------------- | ------------------------------------------ |
| **API key**                | External developers, API clients      | `sapi_key_` prefix                         |
| **OAuth 2.1 access token** | MCP clients (Claude, ChatGPT, Cursor) | Short-lived token issued by the OAuth flow |

Most integrations use an API key. The OAuth flow is only for MCP clients. Tokens that start with `sapi_key_` are treated as API keys; any other token is treated as an OAuth 2.1 access token.

## API keys

API keys are the primary authentication method for external integrations.

### Format

```
sapi_key_<62 hex characters>
```

### Passing the key

Include the key in the `Authorization` header:

```bash theme={null}
curl https://api.social-api.ai/v1/accounts \
  -H "Authorization: Bearer sapi_key_your_key_here"
```

If the key is missing or invalid, the API returns:

```json theme={null}
{
  "error": {
    "code": "auth.invalid_key",
    "message": "invalid or inactive API key"
  },
  "request_id": "a1b2c3d4"
}
```

### Creating keys

Keys are created in the dashboard under **Keys** > **New Key**, or via the API:

```bash theme={null}
curl -X POST https://api.social-api.ai/v1/keys \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production App"}'
```

The full key is returned **once** in `raw_key`. Store it immediately. Subsequent reads only show a truncated preview like `sapi_key_a1b2c...`.

By default a key has full access to every brand and operation. To hand out a least-privilege or client-scoped key, pass `scopes` and `brand_ids` when you create it. See [Scoped API keys](/guides/scoped-keys).

### Rotating keys

Issue a new secret for an existing key without changing its id, name, or restrictions:

```bash theme={null}
curl -X POST https://api.social-api.ai/v1/keys/<key-id>/rotate \
  -H "Authorization: Bearer $SOCAPI_KEY"
```

The new `raw_key` is shown once, and the old secret stops working immediately. To change a key's name or restrictions in place without issuing a new secret, use `PATCH /v1/keys/<key-id>`.

### Revoking keys

```bash theme={null}
curl -X DELETE https://api.social-api.ai/v1/keys/<key-id> \
  -H "Authorization: Bearer $SOCAPI_KEY"
```

A revoked key stops working immediately for all requests.

### Listing keys

```bash theme={null}
curl https://api.social-api.ai/v1/keys \
  -H "Authorization: Bearer $SOCAPI_KEY"
```

The response includes `preview` (suffix only), `is_active`, `last_used_at`, and each key's `scopes` and `brand_ids` restrictions (both empty means full access). See [Scoped API keys](/guides/scoped-keys).

## OAuth 2.1 access tokens (MCP clients)

MCP clients (Claude, ChatGPT, Cursor) authenticate through the API's built-in OAuth 2.1 authorization server instead of a static API key. After the user completes the OAuth flow (see the [OAuth guide](/guides/oauth)), the client receives an access token to send as its Bearer token.

Access tokens expire after **1 hour**. The client uses its refresh token to obtain a new access token without asking the user to re-authorize.

## Authentication error codes

The API returns a consistent set of error codes when a request cannot be authenticated. Use `error.code` for programmatic handling.

| HTTP | Code                      | When it occurs                                                                                                        |
| ---- | ------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| 401  | `auth.missing_header`     | `Authorization` header is absent                                                                                      |
| 401  | `auth.empty_token`        | `Authorization: Bearer` with no token value                                                                           |
| 401  | `auth.invalid_key`        | Token has the `sapi_key_` prefix but does not match any active key                                                    |
| 401  | `auth.invalid_token`      | OAuth access token is invalid or expired                                                                              |
| 401  | `auth.user_not_found`     | Token resolves to a user that no longer exists                                                                        |
| 403  | `auth.dashboard_only`     | Endpoint is available only in the dashboard, not to API keys                                                          |
| 403  | `auth.insufficient_scope` | A [scoped key](/guides/scoped-keys) lacks the scope for this operation, or a restricted key called an admin operation |

See [Error reference](/guides/errors#authentication) for the complete list including OAuth-specific codes.

## Security best practices

* **Never expose keys in frontend code.** Keys must only be used server-side.
* **Use environment variables.** Do not hardcode keys in source code.
* **Create one key per service.** Revoke individual keys if compromised without disrupting others.
* **Grant least privilege.** Restrict a key to the [scopes and brands](/guides/scoped-keys) it actually needs, so a leaked key cannot cross clients or perform actions it never should.
* **Monitor `last_used_at`.** Unused keys should be revoked.
* **Rotate OAuth refresh tokens.** The API enforces refresh token rotation. Each refresh grants a new token pair.
