Licensing & Device Identity¶
How seats work when your app embeds the SDK: what registers a device, what counts as one billable seat, and what an integrator must know about device identity on Android. This page is the integrator-facing product summary only — commercial terms and pricing live in TheStage Android SDK Product Terms; for a quote open a Service Request at app.thestage.ai/contact.
Initialize registers the device¶
initialize must be called before any pipeline will load. A successful
initialize validates the API token online and registers the device — that
online validation is what creates (or re-confirms) the seat.
Surface |
Call |
|---|---|
Kotlin |
|
Flutter |
|
The SDK never persists the API token itself.
Seat = (apiToken, deviceId)¶
A billable seat is the pair (apiToken, deviceId):
The
apiTokenidentifies the customer/developer. Different developers always use different tokens, so two unrelated apps on the same physical device are billed separately — by token, regardless of device-id scope.The
deviceIdidentifies the device to the backend. Product guarantee: reinstalling the same app on the same device is intended to keep the same seat.
Android specifics an integrator should know:
The
deviceIdis a per-install identifier stored in app-private storage. It is stable across launches of the same install.App-private storage is wiped on uninstall, so by default a reinstall produces a fresh
deviceId. A host app can opt into Android Auto Backup (android:allowBackup="true"in its manifest) to restore the samedeviceIdon reinstall.Without Auto Backup, the backend reconciles brief uninstall/reinstall cycles: a device that reappears within a reactivation window reuses its existing seat rather than allocating a new one.
Offline / network¶
The token is validated online once per process (cached in-memory); a fresh app launch always re-validates online. There is no offline grace window — the device must be reachable when
initializeruns, and a transport failure or backend rejection is a hard init failure.Connections are certificate-pinned to well-known public roots, so corporate MITM proxies (custom interception CAs) will break validation.
Device integrity (release builds)¶
On a release build (the embedding app is not debuggable) the SDK runs a best-effort environment check before it loads any engine and refuses to load on an obviously compromised device — rooted, running under an emulator, under an instrumentation/injection framework, or with a debugger attached. It is a deterrence layer; the check never reveals which probe fired.
Debug builds (
android:debuggable="true") never enforce, so development on emulators and under a debugger works normally.A release build that legitimately needs a debugger attached (an instrumented test app) can opt only the debugger probe out with a manifest flag — add the
<meta-data>entry inside your app’s existing<application>element. Root / emulator / injection probes still enforce:<application> <meta-data android:name="ai.thestage.qlip.ALLOW_DEBUGGER" android:value="true" /> </application>
This is for test apps only — do not ship it in a production build.
Quick reference¶
Scenario |
Pair |
Seats |
|---|---|---|
Same app, same device, relaunch |
unchanged |
1 |
Reinstall (Auto Backup on) |
unchanged |
1 |
Reinstall (Auto Backup off) |
new |
server reuses the old seat within the reactivation window; otherwise a new seat |
Two different developers’ apps, one device |
different tokens |
2 |
App relaunch after a prior online validation |
unchanged |
1 (re-validates online each launch) |
Agent Checklist¶
Always
initializebefore starting any pipeline — it registers the device (online validation).One seat =
(apiToken, deviceId); different tokens on one device are different seats.Do not invent your own device registry — the SDK owns device identity.
Do not depend on internal ID derivation or backend field names — they are not part of the public contract.
Pricing / quota changes → open a Service Request at app.thestage.ai/contact.