Skip to content

Initialize the SDK

Every other page links here for initialization, so these are the only copy-paste starting points. Each one compiles against the published SDK in CI.

Which entry point you use depends on where the code runs:

Where it runsEntry pointLocal modeHosted mode
Browser, ReactRevTurbineProvider from @revturbine/sdklocalRuntime: { playbook }publicKey + clientSession
Browser, no ReactinitRevTurbine from @revturbine/sdk/headlesslocalRuntime: { playbook }publicKey + clientSession
Your Node serverinitRevTurbine from @revturbine/sdk/headless, plus RevTurbineServerthe Playbook snapshot you loadedserver key for Playbook delivery and events; RevTurbineServer for client sessions

The option names are fixed, and they are not interchangeable:

OptionWhereWhat it is
publicKeythe browserYour ingest key (rtk_…, type public). Safe to ship in a bundle.
apiKeyheadless server initialization and RevTurbineServerYour server key (rtk_…, type server). Secret. Never in a browser bundle, never a NEXT_PUBLIC_ variable.
localRuntime.playbookanywhereThe Playbook you load yourself (revturbine.playbook.json).
clientSessionthe browserA function that returns a short-lived session token from your server. See Client sessions.

In a browser, initialize with publicKey. On a trusted backend, headless RuntimeMode.Server accepts apiKey for Playbook loading and event ingest. The key never makes a hosted entitlement decision: evaluation runs locally with the user’s context and the loaded Playbook.

  1. Launch a Playbook. Hosted mode serves your launched Playbook: revturbine launch ./revturbine.playbook.json.

  2. Mint an ingest key and list your origins. In the dashboard, open Settings → API Token Management → Ingest Keys and mint a key. Add every origin that will load the SDK to its Allowed origins, including your local dev origin (for example http://localhost:3000). The list is fail-closed: a request from any other origin gets 403 origin_not_allowed, and every check then denies with config_unavailable.

  3. Mint a server key. Under Settings → API Token Management → Server Token. It is shown once. Put it in your server’s environment as REVTURBINE_API_KEY, next to REVTURBINE_TENANT_ID. The tenant id must be the tenant the key belongs to.

  4. Add the client-session route on your server, so the SDK can pick up plan, trial and payment state from Stripe. See Client sessions.

Local mode needs none of this. It is production-capable on its own, and it is the right first step: see Runtime Modes.

Local: the Playbook ships with your app.

src/App.tsx
import { RevTurbineProvider } from '@revturbine/sdk';
import { useMemo } from 'react';
import playbook from './revturbine.playbook.json';
export default function App() {
const options = useMemo(() => ({
localRuntime: { playbook },
user: { id: 'user_123', plan_handle: 'starter' },
}), []);
return (
<RevTurbineProvider options={options}>
<YourApp />
</RevTurbineProvider>
);
}

Hosted: the SDK fetches your launched Playbook with the public key, and the clientSession callback brings in the plan Stripe says the user is on.

src/revturbine-provider.tsx
import { RevTurbineProvider } from '@revturbine/sdk';
import { useMemo, type ReactNode } from 'react';
import { fetchClientSession } from './revturbine-client-session';
export function RevTurbine({ userId, children }: { userId: string; children: ReactNode }) {
const options = useMemo(
() => ({
publicKey: process.env.NEXT_PUBLIC_REVTURBINE_PUBLIC_KEY!,
user: { id: userId },
clientSession: fetchClientSession,
}),
[userId],
);
return <RevTurbineProvider options={options}>{children}</RevTurbineProvider>;
}

user carries only the id: the plan arrives from Stripe through the client session. tenantId is optional, because the key names its tenant. endpoint is optional and defaults to RevTurbine’s hosted control plane. fetchClientSession is the browser half of the client-session flow.

The provider needs a stable options object, so build it with useMemo as above; a new object on every render re-initializes the SDK.

For Vue, Svelte, Angular or plain TypeScript. Same options, no React.

src/revturbine.ts
import { initRevTurbine } from '@revturbine/sdk/headless';
import { fetchClientSession } from './revturbine-client-session';
export async function startRevTurbine(userId: string) {
return initRevTurbine({
publicKey: process.env.NEXT_PUBLIC_REVTURBINE_PUBLIC_KEY!,
user: { id: userId },
clientSession: fetchClientSession,
});
}

initRevTurbine is asynchronous and resolves to a session. Use it directly (await session.can('export')), or reach the core SDK as session.sdk. For local mode, swap the two hosted options for localRuntime: { playbook }.

A server has two jobs, and they use two different objects.

Decide whether a user may do something, before you do the paid work. The headless SDK evaluates your Playbook in-process, for one user per instance. Load the Playbook once per process and build a request-scoped instance:

src/server/revturbine.ts
import {
initRevTurbine,
RuntimeMode,
type RevTurbineUserContext,
} from '@revturbine/sdk/headless';
import playbook from './revturbine.playbook.json';
/** One instance per request: the SDK holds a single user context per instance. */
export function revturbineFor(user: RevTurbineUserContext) {
return initRevTurbine({
runtimeMode: RuntimeMode.LocalOnly,
localRuntime: { playbook },
user,
});
}

Get the Playbook with revturbine download --live --save ./revturbine.playbook.json in your build or deploy step, so the server evaluates the Playbook you last launched. A launch reaches a server when it next loads that file, so restart or redeploy after a launch. The full local and connected patterns are on Server-Side Integration.

Mint client sessions and write server-only user state with your server key. RevTurbineServer is one long-lived object per process, not one per request:

src/server/revturbine-server.ts
import { RevTurbineServer } from '@revturbine/sdk/headless';
export const revturbineServer = new RevTurbineServer({
tenantId: process.env.REVTURBINE_TENANT_ID!,
apiKey: process.env.REVTURBINE_API_KEY!,
endpoint: process.env.REVTURBINE_ENDPOINT ?? 'https://revturbine.com/app',
});

RevTurbineServer does not evaluate anything. What it can do: mint client sessions (clientSessions.create), assign a seat type (assignSeatType), write built-in dimensions (setBuiltinDimensions) and read them back (getBuiltinDimensions). The server key stays in server code.

For hosted Playbook updates, use the server runtime after authenticating the caller and constructing their context from trusted application data:

TypeScript
import { initRevTurbine, RuntimeMode, type RevTurbineUserContext } from '@revturbine/sdk/headless';
export async function canExport(user: RevTurbineUserContext): Promise<boolean> {
const session = await initRevTurbine({
runtimeMode: RuntimeMode.Server,
tenantId: process.env.REVTURBINE_TENANT_ID!,
apiKey: process.env.REVTURBINE_API_KEY!,
user,
analytics: false,
anonymousTelemetry: false,
});
try {
if (session.sdk.getPlaybookLoadFailure()) return false;
return (await session.can('data_export')).allowed;
} finally {
session.sdk.dispose();
}
}

Keep an identified session scoped to that user and operation. Share immutable Playbook snapshots, not sessions, between callers. A connected instance treats localRuntime.playbook as a startup seed and refreshes it from hosted delivery; LocalOnly continues using the supplied snapshot without fetching.

The cloud integration tutorial adds authenticated context tokens, an explicitly bounded shared Playbook cache, and provider adapters.