Skip to main content
Ottili ONE API

Public API authentication & API keys

How to authenticate against the public Ottili ONE Developer API, create and store API keys, use scopes and headers, rotate and revoke keys, and handle common errors.

The public Ottili ONE Developer API* is the approved, documented developer contract for Ottili ONE. It is separate from the internal Unified API: only the endpoints under the public base path are intended for external developers, and internal admin, debug and local-development routes are never part of this surface.

This guide covers everything you need to authenticate and manage API keys: account and company requirements, creating a key, storing it safely, the request headers, scopes, rotation, revocation, environments, and the most common errors.

The Developer API is in public beta*. Endpoint paths and scopes are stable, but limits and metadata may evolve. The live GET /api/v1/developer endpoint is the source of truth for the current version, status and endpoint index.

1. Base URL

All public Developer API endpoints are served from the public host and base path:

https://api.ottilione.com/api/v1/developer

This surface documents only the public developer contract. Internal Unified API routes, admin endpoints, dashboard routes and local-development paths are intentionally not* part of this surface.

2. Account and company requirements

Before you can create API keys you need:

  • A verified Ottili user account* (see [Account & login](/docs/account-and-login)).
  • Membership in an active or trial company* (see [Company & team](/docs/company-and-team)). The company must not be suspended or archived.
  • An active workspace* inside that company (not suspended or archived) — see [Workspaces & modules](/docs/workspace-and-modules).
  • A role that may use the Developer API: a developer/platform-developer/platform-admin role, a company owner or company admin, or a superadmin.

API keys are bound to your user membership*. They are not floating credentials: every key resolves to the company and workspace context of the user who created it. Keys also cannot be used to manage other keys — creating, listing, revoking or rotating a key always requires a user token*, never another API key.

3. Authenticate a request

Every authenticated request sends the key in the standard Authorization header:

Authorization: Bearer ott_your_api_key_here

Two credential types are accepted:

  • API keys* — prefixed with ott_, shown only once at creation, stored hashed at rest.
  • JWT bearer tokens* — issued by Ottili Auth for user sessions (used for key management itself).

If a request needs a company or workspace other than the key's default, you select it with headers (resolved from the key owner's verified membership):

X-Platform-Company: your-company-slug
X-Platform-Workspace: your-workspace-slug

Query-parameter equivalents (company_slug, workspace_slug) are also accepted. Raw numeric company-ID headers are ignored* — the API resolves context from the verified membership, never from an untrusted header.

A missing or invalid credential fails closed with 401.

Example: list your company's modules

curl "https://api.ottilione.com/api/v1/developer/modules" \
  -H "Authorization: Bearer ott_your_api_key_here" \
  -H "X-Platform-Company: your-company-slug" \
  -H "X-Platform-Workspace: your-workspace-slug"

4. Scopes

Keys are granted scopes* that limit what they can do. Request only the scopes your integration needs.

Scope groupScopesAllows
Readdeveloper:read, modules:read, platform:readRead metadata, modules, capabilities and usage
Executedeveloper:execute, modules:execute, module:executeRun module actions
Admindeveloper:admin, platform:adminManage API keys (create, list, revoke, rotate)
Debugdeveloper:debug (also granted by admin scopes)Inspect request traces

A request whose key lacks the required scope is rejected with 403 and a DEVELOPER_SCOPE_REQUIRED code. The wildcard * matches every scope in a group (for example module:* matches module:execute).

5. Create an API key

Key creation requires a user token* (not an API key) and the admin* scope, in an active company context.

curl -X POST "https://api.ottilione.com/api/v1/developer/api-keys" \
  -H "Authorization: Bearer <user-jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Integration",
    "scopes": ["developer:read", "module:execute"],
    "expires_days": 90
  }'

Request body:

  • name (required, 1–100 chars): a human-readable label, e.g. Production Integration.
  • scopes (optional): list of scopes; empty means read-only by default.
  • expires_days (optional, 1–365): expiration in days. Omit for a key that does not expire.

Response (the rawKey is shown only once*):

{
  "keyId": 123,
  "rawKey": "ott_example_api_key_xyz123",
  "keyPrefix": "ott_",
  "name": "Production Integration",
  "scopes": ["developer:read", "module:execute"],
  "role": "developer",
  "expiresAt": "2026-08-15T00:00:00Z",
  "createdAt": "2026-05-15T00:00:00Z"
}

Copy the rawKey immediately. It is never returned again — listing keys returns only the prefix and metadata.

6. Store keys safely

Treat an API key like a password:

  • Copy it on creation.* The raw key is shown only once and cannot be recovered.
  • Use a secret manager.* Store it in your environment variables, a vault, or your CI secret store — never in source control, client-side code, logs, or chat.
  • Scope tightly.* Grant the minimum scopes your integration needs (see [Roles & permissions](/docs/roles-and-permissions)).
  • Set expirations* for keys that do not need to live forever.
  • Rotate on leak.* If a key may be exposed, revoke or rotate it immediately (sections 8–9).

7. List your keys

curl "https://api.ottilione.com/api/v1/developer/api-keys" \
  -H "Authorization: Bearer <user-jwt>"

Returns every key you own with its prefix, name, scopes, active state, expiration and last-used time. Raw keys are never included.

8. Rotate a key

Rotation issues a new key with the same scopes and expiration*, then immediately revokes the old one. Use it to roll credentials without changing scope configuration.

curl -X POST "https://api.ottilione.com/api/v1/developer/api-keys/123/rotate" \
  -H "Authorization: Bearer <user-jwt>"

The response contains a new rawKey (shown only once) and revokedKeyId pointing at the old key. Update your integration to the new key, then retire the old one — the old key stops working as soon as the rotation completes.

9. Revoke a key

Revocation permanently disables* a key. This cannot be undone; a revoked key is gone and a new one must be created.

curl -X DELETE "https://api.ottilione.com/api/v1/developer/api-keys/123" \
  -H "Authorization: Bearer <user-jwt>"

Revocation is audited. Only keys you own can be revoked, and only with a user token plus the admin scope.

10. Environments

The public Developer API is served from a single production surface* (public beta). There is no separate sandbox or staging host in the approved public contract, so do not hard-code different base URLs per environment.

To separate environments in your own systems:

  • Create a distinct key per environment* (for example Staging Sync, Production Sync) with its own name and minimal scopes.
  • Keep production credentials out of non-production deployments.
  • Prefer rotation* over long-lived shared keys when promoting between environments.

11. Rate limits

  • Public discovery* endpoints (the index and public catalog) allow 120 requests per 60 seconds per client IP.
  • Authenticated* endpoints are rate-limited per key/identity. When you exceed a limit the API responds with 429 Too Many Requests and a Retry-After header telling you how many seconds to wait.

Back off and retry after Retry-After; do not tight-loop on 429.

12. Common errors

StatusCode / causeWhat to do
401Missing, malformed or expired credentialSend a valid Authorization: Bearer ott_... (or a fresh user JWT).
403DEVELOPER_SCOPE_REQUIREDThe key is missing the scope the endpoint needs. Recreate the key with the required scope.
403DEVELOPER_ROLE_REQUIREDYour identity may not use the Developer API. Use a developer/company-admin role or superadmin.
403CANNOT_CREATE_KEY_FROM_API_KEY / CANNOT_LIST_KEYS_FROM_API_KEY / CANNOT_REVOKE_KEY_FROM_API_KEY / CANNOT_ROTATE_KEY_FROM_API_KEY / CANNOT_VIEW_KEY_USAGE_FROM_API_KEYKey management must use a user token*, not another API key.
403COMPANY_INACTIVE / WORKSPACE_INACTIVEThe company or workspace is suspended/archived. Reactivate it first.
403COMPANY_CONTEXT_NOT_FOUND / WORKSPACE_CONTEXT_NOT_FOUNDThe company/workspace slug is missing or not accessible. Send X-Platform-Company / X-Platform-Workspace.
403USER_REQUIRED / USER_BOUND_API_KEY_REQUIREDKeys must be bound to a verified user membership.
404KEY_NOT_FOUNDThe key id does not exist or is not owned by you.
429Too Many RequestsRespect the Retry-After header and back off.
500Internal errorRetry with a short delay; if it persists, check [status](https://ottili.one/status) and contact support.

Every error response includes a machine-readable code, a human-readable message, and a requestId you can share with support for tracing.

Related

  • The OpenAI-compatible [Ottili AI API](/docs/ottili-ai-api) uses the same ott_ key format for model calls.
  • Manage your [account & login](/docs/account-and-login), [company & team](/docs/company-and-team) and [workspaces & modules](/docs/workspace-and-modules).

Was this article helpful?