SMAO API Documentation

Authentication

Organization API keys for the Public API, SMAO-issued bearer keys for the Distributor API.

The two APIs use two independent auth schemes — a Public API key never works against the Distributor API and vice versa. Both are sent the same way: Authorization: Bearer <key>. Newly issued Public API keys are ~43-character base64url strings with no prefix; legacy smao_-prefixed Public API keys remain valid.

Public API — organization API keys

Create keys yourself in the dashboard under Settings → API Keys → New key. Each key gets a Role that scopes what it can do — pick the narrowest role that covers your use case. Keys belong to one organization; every request is scoped to that organization's data.

curl https://api.smao.ai/api/v1/ping \
  -H "Authorization: Bearer YOUR_API_KEY"

A missing or invalid key returns 401:

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

A valid key whose role lacks permission for the endpoint returns 403 with error.code: "forbidden". See Errors for the full envelope.

The raw key is shown once, at creation. Store it in a secret manager — it cannot be retrieved later.

Key handling:

  • One key per integration. Separate keys let you revoke one consumer without breaking the others.
  • Rotate by overlap. Create a new key, deploy it, then delete the old one. Both work in parallel in between, so rotation needs no downtime.
  • Revoke immediately on leak. Deleting a key invalidates it at once.

Distributor API — distributor keys

Distributor keys are issued by SMAO during onboarding — there is no self-service issuance. The raw key is shown exactly once at creation; the server stores a SHA-256 hash plus the first 12 characters as an identification prefix — never the full key.

Each key is issued for one Distributor API contract version. Calling the other version returns 403 API_VERSION_NOT_ALLOWED.

v2 keys carry this fixed permission set:

  • organizations:read
  • organizations:write
  • usage:read

Compatibility v1 keys also carry partners:read and partners:write for the partner-based endpoints. Permission sets are immutable after issuance.

Keys expire, by default after 365 days. Request a replacement key from SMAO before expiry and switch over — old and new keys work in parallel until the old one expires or is revoked, so rotation needs no downtime.

curl https://api.smao.ai/api/distributor/v2/organizations \
  -H "Authorization: Bearer YOUR_DISTRIBUTOR_KEY"

Auth failures return 401 in the Distributor error envelope, with an errorCode telling you why:

{ "status": "error", "errorCode": "INVALID_API_KEY", "message": "Invalid or revoked API key." }
errorCodeMeaning
MISSING_API_KEYNo Authorization: Bearer header, or an empty key.
INVALID_API_KEYKey unknown or revoked.
API_KEY_EXPIREDKey past its expiry date — request a replacement from SMAO.
API_VERSION_NOT_ALLOWEDThe key belongs to the other Distributor API version, or has invalid version metadata.

Only GET /health is public in each version; every other Distributor endpoint requires a version-matched key. See the v2 overview, v2 quickstart, and v1 quickstart.

Comparison

Public APIDistributor API
IssuanceSelf-service: dashboard Settings → API KeysBy SMAO during onboarding
ScopingOne organizationAll organizations managed by the distributor
PermissionsRole-based, chosen per keyFixed per version; v1 additionally has partner permissions
ExpiryNone365 days by default
RotationCreate new key, deploy, delete oldRequest replacement from SMAO; parallel until old key expires or is revoked
Rate limitsPer key defaults: read 1000/min, write 200/min, POST /calls 60/hourPer key: 60 req/min default (configurable per key)
401 shape{ "error": { "code": "unauthorized", ... } }{ "status": "error", "errorCode": "...", "message": "..." }

For the Public API, matched operations that pass authentication and the feature gate return X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset after the limiter succeeds. Auth failures, feature-gate failures, unmatched routes, and limiter-storage failures do not carry the full header set. Details in Errors.

On this page