Authentication
Every Saaya API call is authenticated with a bearer token and scoped to a single organization. There are no anonymous endpoints, no implicit org context, and no cookie-based auth on the API surface.
API keys
API keys are minted from `Settings → API Keys` in the dashboard at app.saaya.ai. Two prefixes are issued: `sk_live_` for production and `sk_test_` for sandbox traffic. Keys carry the org id they were minted under and inherit the role of the minting user.
curl https://api.saaya.ai/api/v1/agents \
-H "Authorization: Bearer sk_live_..." \
-H "X-Organization-Id: org_2N3rH..." \
-H "Content-Type: application/json"Never embed live keys
The X-Organization-Id header
Saaya is multi-tenant by default. Even with a valid bearer token, every request must declare which organization it acts on via `X-Organization-Id`. The backend rejects mismatches at the request-context layer, there is no "default org" fallback.
Scopes
Keys can be minted with one of four scopes that mirror the org-role model: `read`, `agents:write`, `sessions:write`, and `admin`. Most production integrations use `agents:write` + `sessions:write`. Reserve `admin` for back-office automation that needs to mint keys or rotate webhooks.
- `read`, list and inspect agents, sessions, knowledge bases, campaigns.
- `agents:write`, create, update, publish, rollback, delete agents and KBs.
- `sessions:write`, start sessions, stream messages, dispatch test calls, run campaigns.
- `admin`, mint keys, rotate webhook secrets, edit RBAC, manage org settings.
SDK helpers
The TypeScript and Python SDKs read `SAAYA_API_KEY` and `SAAYA_ORG_ID` from the environment by default, so you only configure them in one place.
import { Saaya } from "@saaya/sdk";
// Reads SAAYA_API_KEY + SAAYA_ORG_ID from process.env automatically.
export const saaya = new Saaya();
// Or pass them explicitly:
export const saaya2 = new Saaya({
apiKey: process.env.SAAYA_API_KEY,
orgId: process.env.SAAYA_ORG_ID,
});Rotation
Treat keys like passwords. Rotate them every 90 days, on any team-membership change, and immediately on suspected exposure. Saaya supports overlapping keys, mint the new key, deploy it, then revoke the old key, so you can rotate with zero downtime.
// 1. Mint a new key (keep the old one alive for now).
const fresh = await saaya.apiKeys.create({ scope: "agents:write" });
// 2. Roll fresh.value into your secret manager and redeploy.
// 3. Revoke the old key once nothing in production references it.
await saaya.apiKeys.revoke(oldKeyId);Login lives elsewhere