Skip to content

Authentication

Every request carries a bearer token:

Authorization: Bearer aik_S3cr3tT0k3nValueShownOnceDoNotShare1234

Any Bearer token beginning with aik_ is handled by the API-key authenticator and never falls through to Firebase — so a mistyped key fails as a key, with a key-shaped error, rather than as “invalid Firebase token”.

flowchart TB
    T["Authorization: Bearer …"] --> P{"starts with<br/>aik_ ?"}
    P -->|yes| K["API-key auth"]
    P -->|no| F["Firebase auth"]
    K --> V{"key live, and<br/>plan entitled?"}
    V -->|yes| OK["team-scoped access"]
    V -->|"revoked or typo'd"| E1["401 Invalid API key"]
    V -->|"plan downgraded"| E2["401 requires Organization"]
    OK --> H{"human-only<br/>endpoint?"}
    H -->|yes| E3["403 not available<br/>to API-key callers"]
    H -->|no| Y["200"]

Minting is owner-only and requires the Organization plan or above. The team owner does it in the app under Settings → API keys, or over HTTP from a signed-in session:

Terminal window
curl -X POST https://api.ai.aikynetix.app/api/api-keys/ \
-H 'Authorization: Bearer <firebase-id-token>' \
-H 'Content-Type: application/json' \
-d '{"label":"production webhook"}'
{
"id": "9b1c7e2a-4d3f-4a8b-9c0d-1e2f3a4b5c6d",
"label": "production webhook",
"token": "aik_S3cr3tT0k3nValueShownOnceDoNotShare1234",
"created_at": "2026-04-30T08:00:00Z"
}

Two things can refuse that call, both owner-facing rather than integration-facing: {"detail": "Only the team owner can manage API keys"} if you are a member rather than the owner, and {"detail": "api_keys_require_upgraded_plan"} if the team’s tier does not carry API access. Listing and revoking stay available on every tier, so an owner who downgraded can still audit and clean up.

Mint the new key, deploy it, then revoke the old one with DELETE /api/api-keys/{id}/. Revocation takes effect on the next request.

Managing keys is a human-session surface: an aik_… token cannot list, mint or revoke keys — not even its own.

Everything team-scoped that a coach can reach: sessions, athletes, client groups, the exercise catalogue, Solutions, and billing as read-only.

What it cannot reach are the human-shaped surfaces, which answer 403 with {"detail": "This endpoint is not available to API-key callers."}:

  • the signed-in user’s own profile, onboarding and branding
  • team membership, invites and ownership transfer
  • billing actions — checkout, portal, cancel, reactivate
  • the dashboard aggregates and per-session trends
  • the coaching agents, the in-app assistant, and AI artifacts
  • custom metric thresholds
  • API-key management itself

Two consequences worth designing around:

Sessions created by a key have uploaded_by: null. A key is not a person. If you need attribution, keep it on your side.

Aggregation is yours. With the dashboard endpoints closed, trends across sessions are something you compute — the per-session data is all there.

A downgrade stops the key working immediately, on the next request:

{ "detail": "API keys require the Organization plan or higher" }

That is a 401, and it is deliberately worded differently from {"detail": "Invalid API key"} so you can tell a billing problem from a bad credential. The keys are not deleted — they authenticate again the moment the plan is restored, with no re-minting.

Handle these two differently: an invalid key is a code or config problem and retrying never helps; a plan problem needs a human at the customer to act.