Reactor.fetchJwt, or use a token supplied by their backend.
Get your API key
1
Create an account
Sign up at reactor.inc.
2
Create an API key
Open the Dashboard, click your user icon, then navigate to
API Keys to create a new key.
3
Copy your key
Your key starts with
rk_. Store it securely and never commit it to source control.- JavaScript
- Python
- C++
- Swift
- Java
JavaScript
How it works
Your server exchanges the API key for a short-lived token, which the browser uses to connect. Always mint session-scoped tokens: passauthorization_details naming the models the token may start
sessions for. A scoped token can only create and operate its own sessions — it cannot touch other
sessions, other models, or any account API. If it leaks, the blast radius is a handful of sessions
on the models you listed, for at most the token’s lifetime (1 hour by default).Generate a session-scoped token
Exchange your API key for a short-lived token by making aPOST request to the /tokens endpoint
with your API key in the Reactor-API-Key header. Always scope the token with
authorization_details, naming the models it may start sessions for:Session-scoped (1-hour expiry)
Custom expiry
authorization_details entry has these parts:type: "session"(required) — the only supported type today. The token can create sessions and do everything those sessions need (transport negotiation, uploads, clips, session logs), and nothing else.resources.models.match(required) — a non-empty list of models the token may start sessions for. Every listed model must be visible to your API key. There is no wildcard; list each model explicitly.constraints.max_sessions(optional) — how many sessions the token may create in total, from 1 to 500. Defaults to 5. This counts sessions ever created by the token, not concurrent ones: closing a session does not restore capacity.constraints.max_session_duration_seconds(optional) — cap every session the token creates at this many seconds, from 1 to 86 400 (24 hours). Omit for no limit; if the account also has a maximum, the lower value wins. See Rate limits.resources.sessions.bind(optional) — a non-empty list of IDs of open sessions that the token did not create itself. Required when the token must act on such a session. See Acting on a session another token created.
expires_after (in seconds) to shorten
or extend the lifetime, up to the server ceiling of 6 hours; values at or above the ceiling are
silently clamped. The server still returns 200, so always check expires_at (a Unix epoch
timestamp) on the response to confirm the actual expiry.Server-side proxy
Set up an API route on your server that mints a session-scoped token and returns it to your frontend:app/page.tsx
Acting on a session another token created
A session-scoped token can act on the sessions in its bound set: the sessions it created, plus any named inresources.sessions.bind when it was minted. Requests on a session outside that set return
403, including DELETE /sessions/{id}. To act on a session that a different token created, mint a
token with bind naming that session, then use it:/tokens echoes authorization_details with the bound set and the resolved
max_sessions. Bound IDs are stored on the server and do not appear in the JWT claims.Rules for bind:- Every ID in
bindmust name a session that is still open and that your account owns. A closed, foreign, or unknown ID returns the same403, so the endpoint cannot be used to find session IDs. - The model of each bound session must appear in
models.match. If it does not, the request returns403. max_sessionsdefaults to the number of bound sessions, so the token has no room left to create: it can operate the sessions it was given, butPOST /sessionsreturns403. Pass a largermax_sessionswhen the token also has to create sessions.
Ending a session you did not create
The JavaScript SDK deletes a session only from the client that created it (see Who owns the session). To end it from any other client or server, sendDELETE /sessions/{id} with a token bound to that session as the bearer, as
endSession above does. The JSON body with a reason is optional.A server process that holds the API key does not need a token. It can send the key itself as the
bearer on DELETE /sessions/{id} and end any session under your account. Never do this from a front
end. The API key must stay on your server.Keeping the token fresh for a whole session
jwtToken also accepts a resolver — a function returning a string or a Promise<string> — instead
of a static value. Pass one whenever a session might outlive a single connect: the SDK calls the
resolver again for every later request that session makes (uploads, clip manifests, ICE refreshes,
SDP renegotiation), not just the initial connect.A resolver that mints a fresh token on every call breaks the session the moment it runs: a
session-scoped token can only act on the sessions it created, so a newly-minted token has none
of them bound yet, and the next upload or clip request 403s. Cache the token yourself, and only mint
again once it’s close to expiring:{ cache: "no-store" }
rather than relying on a Cache-Control header to do the memoizing for you. The browser cache is
outside your control — DevTools’ “Disable cache”, an eviction, or a shared proxy can all miss it
silently, and the resolver falls back to minting a token with no sessions bound, 403ing every call
the session makes from then on.Edge case: a session created moments before the cached token expires is orphaned at the next
refresh, because the freshly minted token is not bound to it. Re-mint with
resources.sessions.bind naming that session, as shown in Acting on a session another token
created.Tokens for a queue or admission-control server
If you run an admission-control layer in front of a fixed pool of sessions — a waiting room gating limited GPU capacity, for example — mint a separate token per admitted slot instead of one shared token for the whole pool. Scope each token tomax_sessions: 1 so it can create exactly the one
session it is being admitted into:slotLifetimeSeconds to the slot’s whole lifetime: the time an admitted user might take to
connect, plus the full session duration. Omitting it defaults to 1 hour, and 6 hours is the
ceiling; a session-scoped token can’t be topped up mid-session,
so undersizing this strands the session it created. Hand the resulting jwt to the admitted client
the same way as the server-side proxy above; its connect() call creates the
session and binds it to this token’s grant.If your API key is compromised, rotate it immediately from the
Dashboard. Rotating does not affect active sessions. Need
help? Email us at support@reactor.inc.
Adopting an existing session. If your backend creates a session and hands the
sessionId to a
client, that client must connect with a token bound to the session. See Acting on a session
another token created and
Sessions.