Check access
Gate features using the current customer's active perk grants.
Use the current person's active perk grants to decide what a customer can access in your app. The person snapshot also carries subscription state and purchase history, but perk grants are what you gate on.
The SDK decides what to show on the device. It cannot protect anything a customer can reach by calling your API directly. Those checks belong on your server. See Check access from your backend.
Gate a feature
A perk is available when the person holds a grant for it with status active. Check it by the
perk slug you configured in Studio. This helper reads the current person and checks its active
perks:
suspend fun hasPerk(perkSlug: String): Boolean {
val person = voidhash.getCurrentPerson() ?: return false
return person.hasActivePerk(perkSlug)
}Wrap the check once in a helper like this so your screens stay simple. person.activePerkSlugs
lists every perk the person can use right now.
Gate on perks, not subscription status
Subscription status cannot tell you which features a product unlocks. It also misses access that comes from one-time purchases or manual grants. Active perk grants are the source of truth for access control.
Offline and failure behavior
A failed refresh, whether the device is offline or the server returned an error, is not proof that the customer has no access.
getCurrentPerson() does not throw when Voidhash is unreachable or answers with an error. It
serves the last snapshot it cached, however old, and keeps it until Voidhash itself confirms that
the person does not exist. Use getCurrentPersonState() when you need to know how current the
answer is:
val state = voidhash.getCurrentPersonState()
val hasAccess = state.value?.hasActivePerk("premium") == true
if (state.value == null && state.isExpired) {
// Unknown: nothing is cached and Voidhash could not be reached. Never lock by default.
}A null person that is not flagged isExpired is a confirmed answer: Voidhash has no person for
this identity yet, for example an anonymous visitor who has not bought anything. The SDK caches
that answer like a snapshot, so repeated checks do not each wait on the network.
Read the current person
When you need more than a single perk check, read the full snapshot:
val person = voidhash.getCurrentPerson()The call returns null when no person exists yet for this identity. The snapshot contains
entitlements, subscription state, and purchase history. The grants are in
person.entitlementGrants.
Grant fields
Each entry in entitlements.grants has these fields.
| Field | Meaning |
|---|---|
perkSlug | The perk slug configured in Studio. Compare this one in access checks. |
perkId | The perk's internal id. It is not the slug. |
status | active or expired. |
source | subscription, purchase, or manual. |
sourceId | The subscription, purchase, or manual grant that created it. |
expiresAt | Expiration time, or null for access without an expiry. |
Use subscriptions.current for account UI, such as the current plan or its renewal state. Use
purchases.history when you need to show past transactions.
Refresh behavior
The SDK refreshes the person after purchases, restores, and identity changes. Between refreshes it
serves a cached snapshot. The snapshot is cached for two days and is served stale after five
minutes. Pass forceFetch = true when you need a network round trip:
voidhash.getCurrentPerson(forceFetch = true)