guides

Build a client (iOS, Android, desktop)

TRaX is built to be driven by your own code — including full third-party "thick clients" that produce a show without ever opening our web studio. A rich client doesn't speak one protocol; it speaks several, one per job. This guide is the map: which transport for which task, and how to authenticate each.

The two authentication models — pick by who you are

Before anything else, decide who your code acts as:

You're building… Authenticate as Credential
A first-party app a user logs into (mobile / desktop that produces or controls a show) the user OAuth 2.0 (PKCE) → user access token (JWT), sent as Authorization: Bearer <jwt>
Server-to-server automation / a third-party integration (dashboards, bots, headless jobs) yourself (the developer) an API key: Authorization: Bearer sk_live_… on the /v1 REST API

These aren't mutually exclusive — a mobile app might log the user in with OAuth for live control and call /v1 with the user's token for reads — but the question "am I logging a user in, or running my own automation?" decides your primary path.

Transport map — which API for which job

I want to… Transport How Auth
Control a studio + receive live state (scenes, sources, go-live, presence, chat control) WebSocket connect to the studio control plane (below) user bearer
Publish camera / mic / screen from the app WebRTC WHIP POST an SDP offer to the studio's WHIP endpoint — see WHIP / WHEP media session token (Bearer)
Publish a hardware / OBS / camera feed SRT or RTMP(S) SRT streamid · RTMP session token in streamid / userinfo
Watch the program or a source preview — now WebRTC WHEP POST an SDP offer to the WHEP endpoint — see WHIP / WHEP media read token (Bearer)
Watch at lowest latency — later MoQ (roadmap) not shipped yet; use WHEP today
List / read studios, sources, destinations, stream status; go live / offline REST /v1 the Developer API sk_live_ API key (or user bearer)

Rule of thumb for a thick client: one WebSocket to control a studio and stream its live state; WebRTC (WHIP up / WHEP down) for media; REST (/v1) for headless reads and automation. Stream paths (the studios/{id}/… names you publish and play) follow one grammar — see Stream paths.

Native-app authentication — OAuth 2.0 with PKCE

A first-party app logs the user in against the TRaX identity provider using the Authorization Code flow with PKCE (the standard, secret-less flow for native and single-page apps). You get back a user access token (JWT) and a refresh token; the access token is what every TRaX surface accepts as Authorization: Bearer <jwt>.

Identity provider (dev): https://auth-dev.traxstreaming.live

Purpose Endpoint
Authorize https://auth-dev.traxstreaming.live/oauth/v2/authorize
Token https://auth-dev.traxstreaming.live/oauth/v2/token
End session (logout) https://auth-dev.traxstreaming.live/oidc/v1/end_session

Scopes: openid profile email. You'll register your app (to get a client id and your allowed redirect URIs) with the TRaX team — contact us for a native app registration.

The flow:

  1. Generate a PKCE pair. Create a random code_verifier, then code_challenge = BASE64URL(SHA256(code_verifier)).

  2. Open the authorize URL in a system browser / ASWebAuthenticationSession (iOS) / Custom Tab (Android) — not an embedded webview:

    https://auth-dev.traxstreaming.live/oauth/v2/authorize
      ?response_type=code
      &client_id=<your-client-id>
      &redirect_uri=<your-redirect-uri>
      &scope=openid%20profile%20email
      &code_challenge=<challenge>
      &code_challenge_method=S256
    

    Use a custom URI scheme (com.yourapp://callback) or a loopback redirect for the native round-trip.

  3. Handle the redirect — you receive ?code=<authorization_code>.

  4. Exchange the code for tokens (no client secret — PKCE stands in for it):

    curl -sS https://auth-dev.traxstreaming.live/oauth/v2/token \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d grant_type=authorization_code \
      -d client_id=<your-client-id> \
      -d code=<authorization_code> \
      -d redirect_uri=<your-redirect-uri> \
      -d code_verifier=<code_verifier>
    

    The response includes access_token (a JWT), refresh_token, and expires_in. Store them in the platform keystore (iOS Keychain / Android Keystore), and use grant_type=refresh_token with the same client_id to get a fresh access token before it expires.

Send the resulting access token as Authorization: Bearer <jwt> on the WebSocket upgrade, on WebRTC WHIP/WHEP signaling, and on /v1 REST calls.

This is the same OAuth-PKCE pattern this docs site itself uses to log in — a native app differs only in the redirect (custom scheme / loopback instead of a web /callback page) and in storing tokens in the OS keystore.

Native vs. browser: the header advantage

A native app can set request headers everywhere, which keeps auth uniform:

  • WebSocket — set Authorization: Bearer <jwt> on the upgrade request. (Browsers can't set headers on a WebSocket handshake, so the web client has to fall back to passing the token another way — a native app has no such limit and should use the header.)
  • WebRTC WHIP / WHEP — set Authorization: Bearer <token> on the signaling POST.
  • REST /v1Authorization: Bearer … as usual.

Preferring the header on native keeps the token out of URLs and logs.

Controlling a studio (WebSocket)

Real-time studio control — scenes, sources, going live, presence, chat control, and the live state stream back to your UI — runs over a WebSocket to the studio control plane:

wss://studio-api-dev.traxstreaming.live/api/v1/studios/{studioId}/ws

Open it with the user's bearer token; the server resolves the user's access to that studio once at upgrade, then gates each operation by role. Frames are JSON — request/reply RPCs plus server-pushed realtime events.

The full RPC + event catalog for this surface is first-party/internal today. If you're a logged-in first-party developer, see the internal reference for the exhaustive method and event lists (WS RPCs, WS events, and the private transport map). Third-party apps reach the platform through the public /v1 REST gateway and this WebSocket — never internal service endpoints directly.

Where to go next

  1. Developer API (/v1) — REST reference, endpoint table, API keys, and OpenAPI client generation.
  2. Authentication & session tokens — token claims and how to verify a TRaX-issued token against our JWKS.
  3. WHIP / WHEP — publish and play media over WebRTC.
  4. SRT streamid · RTMP / RTMPS — push a hardware or OBS feed.
  5. Stream paths — the studios/{id}/… path grammar shared by every media transport.

Tell us what you're building — the roadmap follows what the community wants to ship.