Athos Developer Docs
Browser SDK

Browser SDK

Run a live Athos roleplay call in your frontend with @useathos/sdk.

@useathos/sdk is a headless browser SDK. It exposes a small, domain-focused API — a roleplay session with lifecycle events. Your code only ever works with Athos domain concepts (sessions, events, personas).

  • Synchronous create() so you register handlers before any network work starts.
  • A typed, discriminated event union and a stable error-code taxonomy.
  • Microphone selection, mute, and automatic reconnect handling built in.
  • Ships as ESM + CJS with full TypeScript types.

Install

npm install @useathos/sdk

Requirements

  • Browsers: desktop Chromium-based browsers (Chrome, Edge, Brave, Opera, …) and desktop Firefox. Safari and all mobile browsers are rejected by create() with BROWSER_NOT_SUPPORTED — see Browser support.

  • HTTPS: the page must be served over HTTPS (or localhost). On a plain http:// origin the browser withholds the microphone, which the SDK reports as NO_MIC_AVAILABLE.

  • Framework: none required — no React/Vue binding, no global state. Call create() from a click handler or an effect after mount, never during render or server-side rendering (it throws there). Create one session per call.

  • Size: about 5 kB gzipped, plus its voice-transport dependency (about 250 kB gzipped), installed automatically. Both are ESM + CJS.

  • Iframes: if the call runs inside an <iframe>, the frame needs allow="microphone" or the browser denies the microphone (MIC_PERMISSION_DENIED).

  • Content Security Policy: the SDK calls https://app.useathos.ai (to redeem the token) and then opens a WebSocket + WebRTC connection to the voice host returned by that call — currently under *.livekit.cloud; do not hard-code a single hostname. If you set a CSP, allow:

    connect-src https://app.useathos.ai https://*.livekit.cloud wss://*.livekit.cloud

    That covers the token redeem and the signalling (both https:// and wss:// to the voice host). The audio itself travels over WebRTC, which CSP does not govern, and is played through an <audio> element the SDK creates — no media-src entry is needed.

The five-line integration

import { AthosRoleplay } from '@useathos/sdk';

const token = await getAthosToken();                         // 1. your backend mints a token
const session = AthosRoleplay.create({ token, drillKey: 'ma-full-sale' }); // 2. create (sync)
session.on('ready', ({ persona }) => console.log(`${persona.name} is ready`)); // 3. handlers
session.on('ended', ({ durationSec }) => console.log(`done in ${durationSec}s`));
await session.connect();                                     // 4. join the call

getAthosToken() is your endpoint — it calls POST /v1/session server-side and returns the token. The browser never sees your API key. See minting tokens.

Always register handlers before connect(). create() does no network work, so nothing is missed; connect() is what redeems the token and joins the call.

AthosRoleplay.create(options)

Creates a session synchronously. On an unsupported environment it throws BROWSER_NOT_SUPPORTED straight away, so call it on the client only (see Browser support).

Prop

Type

The session object

create() returns a session with these methods:

MethodDescription
connect()Redeem the token and join the call. Returns a Promise<void>.
disconnect()End the call and leave cleanly. See How a call ends.
on(event, cb)Subscribe to an event. Returns an unsubscribe function.
off(event, cb)Unsubscribe.
listMicrophones()Enumerate available mics. See Microphone & audio.
setMicrophone(deviceId)Switch mic mid-call without dropping.
mute() / unmute()Mute / unmute the local mic.
resumeAudio()Resume playback after AUDIO_PLAYBACK_BLOCKED (call from a user gesture).

How a call ends

The AI persona never hangs up. It has no way to decide the conversation is finished — that is deliberate, because whether a rep's call is over is your product's decision, not a model's. So a call ends in exactly three ways:

  1. You call session.disconnect() — the normal ending. Wire it to an "End call" button.
  2. The two-hour ceiling — a backstop for abandoned calls, not a normal ending. A full-sale roleplay usually runs a few minutes.
  3. The network drops and does not recover within 30 seconds (NETWORK_LOST).

All three fire the ended event with the public callId, including the disconnect() you called yourself. That event is how your UI learns the call is over, and the callId is what ties it to the score that arrives later.

Ship the "End call" button. Without one, a rep who walks away leaves the call running until the two-hour ceiling: you are billed for the full two hours and it counts against your monthly usage allowance. disconnect() is the only way to end a call early.

What's next

On this page