Permissions & consent
The 12 Phone permission scopes, how apps declare them, how players grant them, and the audit trail behind every grant.
Every sensitive Phone SDK call is gated by a permission scope. An app can only use a scope if
it (1) declared it in its manifest and (2) the player granted it.
Calls without permission return empty/null rather than throwing — so your app degrades gracefully.
The scopes
Prop
Type
How granting works
Declare the scopes in your manifest's permissions array. Requesting a scope you didn't declare
is an error.
Default grants. account.basic is always granted. Built-in apps get all their declared scopes by
default. Third-party apps start with only account.basic — everything else needs the player's
explicit consent.
Request at point of use. Ask for a scope when the feature is first used, and check the result:
const granted = await phone.permissions.request("media.pick");
if (!granted.includes("media.pick")) {
phone.ui.toast("Media access is needed to attach a photo.");
return;
}Players manage grants in Settings → the app's permission list, and can revoke any scope except
account.basic at any time.
Checking permissions
await phone.permissions.list(); // → granted scopes for this app
await phone.permissions.has("wallet.read"); // → booleanBecause ungranted calls return empty values, you can also just try and handle the empty result — but checking first lets you show better UI.
Consent-gated messaging
messages.send_with_consent is deliberately named: sending messages on a player's behalf is
sensitive, so every send is audited and the player can revoke the scope to immediately cut an app
off. Build messaging features assuming the player is watching who they message.
The audit trail
Every permission-relevant event is recorded — grants, revocations, denied calls, and calls to undeclared scopes:
type PhonePermissionAudit = {
appId: string;
scope: PhonePermissionScope;
outcome:
| "granted" | "denied" | "undeclared"
| "consent_granted" | "consent_revoked" | "consent_denied";
reason: string | null;
createdAt: string;
};Players can review this in Settings; it's also what powers abuse investigations. For developers, the takeaway is simple: declare only what you use, and request it in context — over-asking shows up in the audit log and erodes trust (and store standing).
Runtime & the bridge
How phone apps actually run — the sandboxed iframe model, the postMessage bridge, the bootstrap snapshot, and lifecycle events.
Phone SDK reference
Every Helix Phone SDK namespace and method — runtime, account, permissions, storage, notifications, media, camera, wallet, payments, contacts, messages, calls, presence, social, feeds, ui, and lifecycle.