Concepts
Entitlements
An entitlement answers one question: does this user have access to this product right now, and until when? Aroli computes it from a ledger of grants using a small set of exact rules.
The model
Every time a user gains access - by redeeming a license key, or when you grant time from the dashboard or the management API - Aroli appends a grant to an append-only ledger. The entitlement for a product (its status and expiresAt) is recalculated from that ledger, so it is always explainable.
Grant durations offered in the dashboard are 1, 7, 30, 90, 180 or 365 days, any custom number of days, or lifetime (durationDays: null).
The rules
- Grants are applied in creation order. The oldest grant is applied first.
- Time stacks and never overlaps. A timed grant starts at
max(grant time, current expiry). If the user still has time left, the new time is added after it. - After a lapse, time starts fresh. If the entitlement had already expired when the grant was made, the grant starts at the grant time - the expired gap is not back-filled.
- Lifetime wins. A lifetime grant makes the entitlement lifetime (
expiresAt: null). - Freezing pauses the clock. While frozen, the entitlement is inactive and no time is consumed. Unfreezing pushes the expiry forward by exactly the frozen duration.
- Revocation is precise. Revoking a license withdraws only the time that license granted; time from other grants is untouched.
Examples
Stacking
Redeem a 30-day key, then a 90-day key on day 10
After a lapse
A 30-day grant expires; 20 days later the user redeems another 30-day key
Freezing
Freeze for 14 days in the middle of a 90-day period
Revocation
Suppose a user redeemed key A (30 days) and key B (90 days), stacked to 120 days. If you revoke key A, the entitlement is recalculated without key A's grant: the user keeps key B's 90 days, measured from when key B was granted under the rules above. Nothing granted by other keys or manual grants is removed.
Lifetime grant
Checking access
In your app, call session.hasEntitlement("pro") (SDK) or GET /api/v1/client/entitlements/pro. The response includes active, status (ACTIVE, FROZEN, EXPIRED, REVOKED or NONE) and expiresAt.
Webhook
Whenever an entitlement changes, Aroli emits an entitlement.changed webhook - useful if your backend mirrors access.