Athos Developer Docs
Backend

Minting session tokens

Exchange your API key for a short-lived session token the SDK can use.

The browser SDK can't hold your API key, so your backend mints a short-lived, single-use session token for it. Expose this as your own endpoint that your authenticated frontend calls.

A token is minted for a registered agent. Register each rep once with POST /v1/agents before their first practice call, then mint with either of the agent's two ids.

POST /v1/session

POST https://app.useathos.ai/api/external/v1/session
Authorization: Bearer ath_live_…
Content-Type: application/json

Request body

Exactly one of:

Prop

Type

Sending neither, or both, is 400 INVALID_REQUEST. null is treated as omitted.

The mint takes an id and nothing else — no agency id (the agency is derived from the agent), and no NPN or email. To mint from an NPN or an email, resolve it to an id first with GET /v1/agents.

Response 200 OK

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "expiresAt": "2026-06-05T18:05:00.000Z"
}

Implement your token endpoint

Wrap POST /v1/session in your own authenticated endpoint so the API key stays on your backend and you decide which rep the token represents.

curl -X POST https://app.useathos.ai/api/external/v1/session \
  -H "Authorization: Bearer $ATHOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"platformAgentId":"rep_8842"}'
// Your endpoint, e.g. POST /athos/token
app.post('/athos/token', requireAuth, async (req, res) => {
  const r = await fetch('https://app.useathos.ai/api/external/v1/session', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.ATHOS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      platformAgentId: req.user.id,         // the id you registered the rep under; never client-supplied
    }),
  });
  const body = await r.json();
  res.status(r.status).json(body);          // { token, expiresAt } on success
});
# Your endpoint, e.g. POST /athos/token
import os, requests

@app.post("/athos/token")
@require_auth
def athos_token():
    r = requests.post(
        "https://app.useathos.ai/api/external/v1/session",
        headers={"Authorization": f"Bearer {os.environ['ATHOS_API_KEY']}"},
        json={
            "platformAgentId": current_user.id,       # the id you registered the rep under; never client-supplied
        },
        timeout=10,
    )
    return r.json(), r.status_code   # { "token": ..., "expiresAt": ... }

Always derive the id you mint with from your authenticated session, not from the request body. A token scopes a live call to that rep; letting the client choose it lets one rep impersonate another.

Rules of the road

  • Mint at the moment of use. The token lives ~5 minutes and is single-use. Mint it when the rep clicks "start practice", hand it straight to AthosRoleplay.create({ token, drillKey }), and connect.
  • One token per call. Reusing a token returns TOKEN_ALREADY_USED at the SDK.
  • Server-to-server only. This endpoint is not CORS-enabled (no Access-Control-Allow-Origin), so a browser blocks the response — it must be called from your backend.

Errors

StatuscodeCause
400INVALID_REQUESTNeither or both of agentId / platformAgentId, or a blank one.
401INVALID_API_KEYBad or missing API key.
401API_KEY_REVOKEDThe key was revoked — rotate.
403TENANT_INACTIVEYour tenant is inactive.
403IP_NOT_ALLOWEDOnly if an IP allowlist is configured for your tenant: the request came from an address outside it.
403TENANT_QUOTA_EXCEEDEDYour tenant's monthly usage allowance is spent.
404AGENT_NOT_FOUNDNo agent of yours is registered under that id. Register the rep first, or resolve an NPN or email to an id with GET /v1/agents.
500INTERNAL_ERRORAn unexpected error. Retry; if it persists, contact Athos with the requestId.

TENANT_QUOTA_EXCEEDED issues no token and is not retryable — the allowance lifts at the start of the next calendar month, or when your Athos contact raises it. It is measured in call minutes across your whole tenant, practice and real calls alike. Surface it to the rep as "practice is unavailable this month". Full envelope and list: error reference.

On this page