# Authentication and keys

Page: https://docs.sonecentral.com/en/kimlik-dogrulama
Markdown: https://docs.sonecentral.com/en/kimlik-dogrulama.md

> Server and publishable keys, authentication headers, allowed origins and revocation.

## Two key types

| | Server key | Publishable key |
| --- | --- | --- |
| Format | `sk-sone-v1-` followed by 48 letters or digits | `pk-sone-v1-` followed by 48 letters or digits |
| Use | Backend, serverless function or script | Website chat widget |
| From a browser | Rejected (`403 secret_key_in_browser`) | Allowed origins only |
| Find conversations with `user` | Supported | Ignored |
| Developer context | Supported | Ignored |
| History imported into a new conversation | Visitor and assistant messages | Visitor messages only |
| Request limit | 120 per minute per key | 30 per minute per visitor address; 1,200 requests and 20,000 reads per hour per key |
| Automatic reply limit | Workspace total: 60 turns/hour, 300/day | Shared across all publishable keys within that total: 40 turns/hour, 200/day |

Create, edit and revoke keys under **Metin asistanı → API anahtarları** (Text assistant → API keys) in Sonecentral. Only workspace administrators see this section. A workspace can have up to 50 active keys; revoked keys do not count.

## Send the key

Use the `Authorization` header:

```http
Authorization: Bearer sk-sone-v1-...
```

`x-api-key` is also accepted. If both are supplied, `Authorization` takes precedence.

```http
x-api-key: sk-sone-v1-...
```

OpenAI SDKs and Vercel AI SDK send their `apiKey` option as `Authorization: Bearer` automatically.

## When the key is shown

The complete key is shown once, at creation. Sonecentral stores only its hash. The list displays its prefix and final four characters. Request logs do not retain the key, whether sent through `Authorization` or `x-api-key`. If lost, create a new key and revoke the old one.

## Rotate a key

Open [Text assistant → API keys](https://app.sonecentral.com/text-agent#api-anahtarlari) as a workspace administrator. Create a replacement with the required assistant scope, allowed origins and request permission. Copy it once, update your integration and verify it with `GET /key`, then revoke the old key. Rotation uses create-and-revoke; there is no separate rotate button. If a key is exposed, revoke it immediately.

Key-management responses use `Cache-Control: no-store`. Requests carrying `Origin: null` (for example from an opaque or sandboxed browser context) are refused; server requests omit `Origin`.

## Key settings

- **Name.** Up to 80 characters to identify the key. Also returned by `GET /key`; do not include secrets.
- **Type.** Server or publishable. Cannot be changed after creation.
- **Assistants.** Which assistants the key can call. Selecting all includes every published workspace assistant, including future ones. You can select an unpublished assistant; the key starts working with it once published.
- **Allowed origins.** Publishable keys only, from 1 to 20 origins.
- **Can receive order and appointment requests.** Enabled by default. The assistant can create requests awaiting your team's approval. When disabled, it passes the details to your team instead. See [Orders, appointments and privacy](https://docs.sonecentral.com/en/siparis-randevu-gizlilik.md).

All settings except type can be edited later. Changes apply on the next request.

## Allowed origins

Browsers send `Origin` automatically on cross-origin requests. A publishable key is accepted only when `Origin` matches its allowlist. It cannot be used without an `Origin` header.

- Use a scheme and hostname, such as `https://www.example.com`. The hostname must contain at least one dot. For a non-443 port, use `https://www.example.com:8443`.
- Paths, query strings, `*` wildcards, IP addresses and `https://localhost` are not accepted.
- `https://example.com` and `https://www.example.com` are separate origins. Add both if needed.
- For development, only `http://localhost` and `http://127.0.0.1` are allowed over HTTP, with or without a port, such as `http://localhost:3000` or `http://127.0.0.1:5173`.

Hostnames are compared in lowercase. An origin outside the allowlist returns `403 origin_not_allowed`.

## Server keys do not belong in browsers

Anyone can read a key embedded in website code and make requests on your behalf. Sonecentral rejects server-key requests carrying an origin not listed on that key with `403 secret_key_in_browser`. The dashboard does not add origins to server keys, so browser-origin requests are rejected. Always use a publishable key in browsers.

This check is a safety net. Pages opened from a local file or a sandboxed frame can send `Origin: null`; Sonecentral rejects these requests too. A client outside the browser can omit or forge `Origin`, so this check does not protect an exposed key. Never include a server key in a browser, mobile app bundle or public repository.

> **Warning**
>
> The OpenAI SDK's `dangerouslyAllowBrowser` option does not bypass this rule. Use a publishable key in a browser.

Browser code can read these response headers: `x-request-id`, `retry-after`, `x-should-retry` and `x-sone-conversation-id`.

## Developer context

With a server key, `system` and `developer` messages, Responses `instructions`, and Vercel AI SDK `context` are passed to the assistant **as information only**. For example, identify the product page the visitor is viewing or their app language preference.

This text cannot override business instructions or rules; instructions embedded in it are not followed. Multiple contexts are joined and limited to 2,000 characters. Responses rejects `instructions` above 2,000 characters or 4 KB of JSON with `400 instructions_too_long`. Context applies only to the current turn; send it again if needed on the next request.

Context sent with a publishable key is ignored and not stored, because visitors can change it.

## Revocation

Revoking a key in **API anahtarları** disables it immediately. Subsequent requests return `401 revoked_api_key`. Revocation cannot be undone and revoked keys cannot be edited. Existing conversations remain in Messages.

Stored responses created by a revoked key expire after 30 days. A new key that can call the same assistant can read them and continue with `previous_response_id`, but cannot delete them or see `instructions`, `safety_identifier` or `user`. See [Stored responses](https://docs.sonecentral.com/en/responses.md#saklanan-yanitlar).

## Inspect the key

`GET /key` returns the current key's summary. Use it to check the workspace and available assistants during setup.

```bash
curl https://pb.sonecentral.com/api/v1/key \
  -H "Authorization: Bearer $SONE_API_KEY"
```

```json
{
  "data": {
    "label": "pk-sone-v1-Ab3…",
    "name": "Web sitesi sohbeti",
    "kind": "publishable",
    "assistants": ["k3m9x2p7q1w8e4r"],
    "requests": true,
    "allowed_origins": ["https://www.ornek.com"],
    "limits": {
      "requests_per_minute_per_visitor": 30,
      "requests_per_hour": 1200,
      "read_requests_per_hour": 20000,
      "assistant_turns_per_hour": 60,
      "assistant_turns_per_day": 300,
      "browser_assistant_turns_per_hour": 40,
      "browser_assistant_turns_per_day": 200
    }
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `label` | string | First 14 characters followed by an ellipsis. No response includes the complete key. |
| `name` | string | Name assigned in Sonecentral. |
| `kind` | "secret" \| "publishable" | secret is a server key; publishable is a browser key. |
| `assistants` | string[] | Currently published, allowed assistant IDs, sorted by assistant name. |
| `requests` | boolean | Whether order and appointment requests are enabled. |
| `allowed_origins` | string[] | Allowed origins. Empty for server keys. |
| `limits` | object | Server keys include requests_per_minute. Publishable keys include requests_per_minute_per_visitor, requests_per_hour (non-read requests), read_requests_per_hour, browser_assistant_turns_per_hour and browser_assistant_turns_per_day. Both include the workspace's assistant_turns_per_hour and assistant_turns_per_day. |

Server-key `limits`:

```json
{ "requests_per_minute": 120, "assistant_turns_per_hour": 60, "assistant_turns_per_day": 300 }
```

`GET /key` is a read and counts toward the key's [limits](https://docs.sonecentral.com/en/limitler.md).

## Errors

| Status | `code` | When |
| --- | --- | --- |
| `401` | `missing_api_key` | No key supplied. |
| `401` | `invalid_api_key` | Unknown or malformed key, or prefix does not match its type. |
| `401` | `revoked_api_key` | Key has been revoked. |
| `403` | `origin_not_allowed` | Publishable key used outside its allowlist or without `Origin`. |
| `403` | `secret_key_in_browser` | Server key used from an origin not listed on the key. |
| `429` | `rate_limit_exceeded` | Request or read limit exceeded. Wait for `Retry-After`. |

All codes: [Errors](https://docs.sonecentral.com/en/hatalar.md).
