Authentication

Every remote request is authenticated with an API key that maps you to a tenant.

API keys

Create and revoke keys in the app under Account → API keys. A key maps every request to a tenant; all stored decks and brand profiles are scoped to that tenant. Keep keys secret. Treat them like passwords; anyone with a key can spend your token quota.

Sending your key

Send the key on every request to the REST (/v1) and MCP (/mcp) doors, using either header:

x-api-key: YOUR_API_KEY
# or
Authorization: Bearer YOUR_API_KEY

Example:

curl https://slides.product-masterclass.com/v1/decks \
  -H "x-api-key: $AGENTIC_SLIDES_KEY"

Failed authentication

A missing or unknown/revoked key returns 401 Unauthorized and no work is done:

{
  "error": {
    "code": "unauthorized",
    "message": "Missing API key."
  }
}

The tenant model

Your key resolves to a tenant id. Most endpoints infer the tenant from the key, so you never pass it. A few endpoints accept an optional tenantId in the body for operators managing multiple tenants; omit it to use the tenant bound to your key.

The model provider key stays server-side

You never send an LLM provider key. The server holds the budget key (a shared key, or a dedicated per-tenant key) and runs generation on your behalf. As a fail-safe, these fields are stripped from request bodies before any handler runs:

apiKey, api_key, anthropicApiKey, baseUrl, budgetKey

So you can never accidentally (or intentionally) override the provider credentials or base URL through the API.

Local development (key-free)

For local work, run the MCP server over stdio. It does not require an API key:

pnpm install
pnpm mcp:stdio

Only the remote HTTP doors (/v1, /mcp) require a key.

Operators can also provision keys via the API_KEYS environment variable as comma-separated key:tenantId[:budgetKey] entries. Self-service keys created in the app are stored hashed (sha256); the raw key is shown once at creation.