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.

POST /v1/session

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

Request body

Prop

Type

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 '{"externalUserId":"rep_8842","externalAgencyId":"agency_chicago"}'
// 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({
      externalUserId: req.user.id,          // never trust a client-supplied id
      externalAgencyId: req.user.agencyId,
    }),
  });
  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={
            "externalUserId": current_user.id,        # never trust a client-supplied id
            "externalAgencyId": current_user.agency_id,
        },
        timeout=10,
    )
    return r.json(), r.status_code   # { "token": ..., "expiresAt": ... }

Always derive externalUserId 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 }), and connect.
  • One token per call. Reusing a token returns TOKEN_ALREADY_USED at the SDK.
  • Server-to-server only. This endpoint rejects cross-origin (CORS) requests — it must be called from your backend.

Errors

StatuscodeCause
400INVALID_REQUESTMissing/blank externalUserId.
401INVALID_API_KEYBad or missing API key.
401API_KEY_REVOKEDThe key was revoked — rotate.
403TENANT_INACTIVEYour tenant is inactive.

Full envelope and list: error reference.

On this page