Skip to content
Download as .md

Role & Permission Hierarchy

Written by Rohman Beny Riyanto

Useful context before you're staring at a 403/424 wondering whether it's a missing permission grant or a role that was never allowed near this endpoint in the first place. See FE Auth Error Handling first for what each code means moment-to-moment - this page is about the model behind them.

Two separate questions, checked separately

Every protected endpoint asks two independent questions, and a 403/424 can come from either one:

The first question is about account type - a customer account can never reach an admin endpoint, full stop, no permission grant changes that. The second is about permissions - within the accounts that are even allowed near the endpoint, does this specific one hold the specific capability it needs. See FE Auth Error Handling for exactly which response_code corresponds to which failure.

The account hierarchy

A sub-role (Staff, Device Admin, or any custom one created later) always starts out with whatever baseline permissions its parent type defines, plus anything explicitly granted to it on top.

Why one merchant never sees another merchant's data

Every permission a merchant-side account holds is scoped to that merchant specifically - never global. A system-level account's permissions apply everywhere; a merchant account's permissions apply only within its own merchant, no matter what's sent in the request.

This has been verified directly, not just assumed: sending an explicit "apply everywhere" scope in a grant/revoke or audit-log request from a merchant account still resolves back to that merchant's own scope - there's no way to make it reach outside. system_owner accounts are the only ones whose scope is genuinely global, and only when acting as root.

Where a permission comes from

Three distinct sources determine what an account can do, and they change at different times - worth telling apart when something isn't behaving as expected:

SourceWhat it meansChanges when
Permission catalogThe full list of object:action pairs that exist at all - see Menu Permission Catalog and Get Permission CatalogWhenever the API itself adds/removes a capability
Default baselineA small set of permissions some sub-roles (like Staff) get automatically, no grant neededFixed per sub-role, doesn't change per account
Explicit grantThe actual "this account/sub-role can do X" assignmentAny time, via Grant Role Permission / Grant User Permission, by someone with the right access

If you're building a Roles & Permissions style admin screen: the catalog tells you what's possible to grant, the baseline is what a sub-role already has without you doing anything, and grants are the thing your UI actually creates/removes.

What each account type can actually do

Verified directly against a running server:

AccountCreate a merchantManage sub-rolesList rolesRegister a sub-accountGrant/revoke permissionsRead audit log
System Super Adminyesyesyesyes, for anyoneyes, anywhereeverything
System Staffno, unless grantedno, unless grantedyes (default)depends on grantdepends on grantdepends on grant
Merchant Super Adminno - wrong account typeno - wrong account typeno - wrong account typeyes, own merchant onlyyes, own merchant onlyown merchant only
Merchant Device Adminnonononono, unless grantedno, unless granted
Customerno - different account type entirelynonononono

A Merchant Super Admin trying to act outside its own merchant - creating a merchant, reaching into another merchant's data, or setting an explicit "global" scope on a grant - is rejected every time, either at the account type check or by having its scope forced back to its own merchant regardless of what the request asked for.