Access and Permissions
Assign dashboard roles, partner reach, and API-key capabilities
Last Updated: 2026-09-03
Version: 1.1
VRPlatform uses the same primitive permission vocabulary for interactive users and API keys, but their bundles are separate grants.
| Grant | Stored on | Purpose |
|---|---|---|
Dashboard role (ui:*) | Team membership | Controls a signed-in user's product access |
Partner API bundle (partner:*) | Partner API key | Controls a backend integration |
| Managed-team reach | Partner membership | Controls which managed teams a user can open |
| Partner deny policy | Managed team | Removes selected partner-derived permissions |
Assigning a dashboard role never changes an API key. Granting an API-key bundle never changes a user membership.
Dashboard Roles
Dashboard roles are versioned ui:* bundles. The API expands the selected
membership's bundles and returns the effective union as
GET /me.membership.permissions.
Broad Team Access
| UI choice | Includes | Does not include |
|---|---|---|
| Team Admin | Standard Member, audit, access admin, and bank setup | ACH execution |
| Standard Member | Product, settings, GL, and banking | Audit, access, bank setup, ACH execution |
Focused Team Access
Use this matrix for Operations and Read Only. View means read access. Other verbs name the additional actions granted in that area. A dash means the role does not grant that workflow.
| Workflow | Read Only | Operations |
|---|---|---|
| Team settings | View | Basic team view |
| Member roster | View | — |
| Integrations and webhooks | View | — |
| Calendar | View | View |
| Files | View | View and upload |
| Listings and contacts | View and export | View |
| Ownerships | View | View |
| Reservations | View and export | View |
| Transactions | View and export | View all; create and edit expenses |
| General ledger | View | — |
| Accounts | View and export | View |
| Tax and mappings | View | — |
| Owner statements | View and export | View, edit, publish, and export |
| Statement layouts | View | View |
| Recurring fees and commissions | View | View |
| Reports and metrics | View and export | — |
| Bank accounts and rules | View | — |
| Bank records | View and export | — |
Read Only includes team discovery so connection details and every listed settings view can resolve the selected team before loading its domain data.
GET /booking-channels supports both Integrations and Recurring Fees. It
accepts either integrations:read or recurring-fees:read, so focused roles
and API keys can resolve fee channel data without receiving integration access.
Transaction writes use one independent permission for each public type:
transactions:expenses:write, transactions:deposits:write,
transactions:transfers:write, and transactions:payouts:write. Operations
receives only the expense permission. A type change requires both type
permissions, and a mixed batch is rejected before any item is written when a
required type permission is absent. Expense payment state still requires the
separate payment permission supplied by ACH Payer.
Additive Privileges
These privileges are independent of team access. They add a sensitive or partner-specific capability and are not substitutes for a team-access role.
| Privilege | Adds | Does not add |
|---|---|---|
| Audit Log | Selected-team public activity history | Other product access |
| Partner Admin | Partner administration and integrations | Team reach or ACH |
| ACH Payer | Record payments and execute ACH | Bank setup or administration |
Partner Admin is available only to partner-team members. It covers partner members, managed teams, sessions, integrations, webhooks, audit, and API keys. ACH Payer is available on every team.
Global VRPlatform administrators cannot save owner or vendor bank details or execute, cancel, or recover ACH payments. Use a direct customer-team membership with Team Admin and ACH Payer when testing those workflows.
A managed team's deny policy can remove ACH execution from partner-derived access even when the partner member has ACH Payer. Direct memberships do not consume that policy.
Stable Bundle Names
| UI label | API catalog title | Bundle name |
|---|---|---|
| Team Admin | Team Admin | ui:team-admin:v1 |
| Standard Member | Standard Member | ui:standard-member:v1 |
| Operations | Operations | ui:operations:v1 |
| Read Only | Read Only | ui:read-only:v1 |
| Read activity history | Audit Log | ui:audit:v1 |
| Manage partner organization | Partner Admin | ui:partner-admin:v1 |
| Execute ACH payments | ACH Payer | ui:ach-payer:v1 |
For exact primitive permission strings, use
GET /team/permission-bundles. Each catalog entry returns its complete
permissions array. The tables above group those strings into UI workflows.
Every current dashboard bundle includes operations:read. There are no
account-specific role assignments in V1.
Build a Role Picker
The API accepts multiple bundles and combines their permissions. The role picker should present exactly one team-access role: Team Admin, Standard Member, Operations, or Read Only. Do not expose the bundle array as an undifferentiated multi-select.
Then render the independent controls:
| Control | Availability | Effect |
|---|---|---|
| Read activity history | Every team | Add Audit Log |
| Manage partner organization | Partner-team members only | Add Partner Admin |
| Execute ACH payments | Every team | Add ACH Payer |
| Managed-team access | Partner-team members only | Select all or assigned teams |
A partner-team member therefore receives Team access, Partner organization, Sensitive permissions, and Managed-team access sections. A non-partner member receives only Team access and Sensitive permissions.
Partner Admin is independent because it governs the parent partner organization; Team Admin governs the selected team's product and administrative access. ACH Payer remains independent because even Team Admin and Standard Member exclude money movement.
This hierarchy is product guidance. Until the API enforces it, clients must still handle existing members with any valid bundle array.
Gate navigation and actions using membership.permissions, never a primary
role, bundle name, or legacy admin/user label. A member with no bundles can
still load GET /me and GET /me/teams, but receives no product permissions.
Role Endpoints
| Task | Endpoint |
|---|---|
| Load assignable roles and expanded permissions | GET /team/permission-bundles |
| Load primitive permission names | GET /team/permissions |
| Replace a member's complete assignment | PUT /team/members/{userId}/permission-bundles |
| Load the selected user's assignment and effective permissions | GET /me |
Team Admins may replace their own assignment, including adding or removing ACH Payer. Removing their own Team Admin access is allowed only when another active direct access manager remains. The same final-manager rule applies to updates of other members.
Invitations and Compatibility Updates
| Action | Bundle behavior |
|---|---|
| Invite in permission mode | Send permissionBundles, including [] when intentional |
| Resend or copy an invitation | Omit permissionBundles to preserve the complete assignment |
| Submit the same legacy role | Preserve the complete bundle assignment |
| Change a legacy role | Replace bundles with that role's compatibility default |
New and legacy non-admin user memberships default to Standard Member. Existing
team admins map to Team Admin, and existing partner-team admins also map to
Partner Admin. Before permission mode is enabled for a user, authorization
continues to follow the legacy role while the API keeps bundle data populated.
An invitation delivery failure does not roll back a committed role change.
Partner-Member Team Reach
A partner member's permissions and team reach are independent. Configure the role picker and managed-team picker as separate controls.
| Reach | Teams available through the partner membership |
|---|---|
all | Every child team managed by the partner |
assigned | Explicitly assigned managed teams only |
assigned with no teams | No managed teams |
Direct or owner membership on a child team remains available independently of partner assignments.
Before permission mode is enabled, users retain legacy broad partner reach.
The stored all or assigned selection takes effect when permission mode is
enabled, without a separate membership migration.
Resolve Access
| Selected-team relationship | Permission source | accessSource |
|---|---|---|
| Direct child-team membership | Child membership's bundles | direct |
Partner all reach | Partner membership's bundles | partnerDerived |
| Explicit partner assignment | Partner membership's bundles | partnerDerived |
| No applicable relationship | No access | Not returned |
A direct membership always wins over partner-derived access. Partner-derived access also applies the selected child team's partner deny policy.
Use GET /me/teams as the authoritative team-switcher source. Use
GET /partner/members to render each partner member's roles, reach mode, and
explicit assignments. Replace managed-team reach through
PUT /partner/members/{userId}/memberships.
| Update | Result |
|---|---|
Select assigned | Replace only the partner-managed team assignments |
Select assigned with teamIds: [] | Remove all partner-derived child-team reach |
Select all | Clear explicit partner assignments and allow every managed team |
| Remove the partner member | Revoke partner-derived assignments |
These changes never delete genuine direct or owner memberships.
Restrict Partner-Derived Access
A directly authorized Team Admin can manage the selected team's partner deny
policy through GET and PUT /team/partner-permission-policy.
| Principal | Policy applies | Can edit policy |
|---|---|---|
| Partner-derived dashboard user | Yes | No |
| Partner API key selecting the team | Yes, after full team enablement | No |
| Embedded session for the team | Yes, after full team enablement | No |
| Direct team member | No | Team Admin only |
The policy stores primitive permission names. A denial wins over a granted bundle. Use it to withhold sensitive actions such as ACH execution, exports, or member-role management. The policy applies team-wide rather than to one bank account or one partner user.
New teams deny ach-payments:execute to partner-derived access by default,
and the same denial is backfilled onto existing teams without replacing other
denials. A directly authorized access manager must explicitly remove that
denial before a partner can execute ACH for the client. Direct team membership
never consumes the partner deny policy.
Partner API-Key Bundles
Partner keys may omit bundles for unrestricted partner access or declare up to the supported reviewed bundles. Restricted keys must have every primitive permission required by an operation.
| Bundle | Domain | Included workflow |
|---|---|---|
partner:accounting-data:v1 | Accounting | Core records, mappings, tax, and fees |
partner:ach-payments:v1 | ACH | Owner payment-method submission and Ramp execution |
partner:audit:v1 | Audit | Redacted public audit events for selected and managed teams |
partner:banking:v1 | Banking | Accounts, connections, Plaid, bank records, rules, and cleanup |
partner:calendar:v1 | Calendar | Read, create, update, and remove blocks |
partner:files:v1 | Files | Read, download, upload, update metadata, and remove files |
partner:general-ledger:v1 | General ledger | Closing, opening balances, and imports |
partner:integrations:v1 | Integrations | Apps, connections, flows, syncs, and imports |
partner:onboarding:v1 | Onboarding | Team onboarding guide and issue operations |
partner:payments:v1 | Payments | Record expenses and owner or manager payouts |
partner:provisioning:v1 | Provisioning | Discover and configure teams; issue sessions |
partner:recurring-fees:v1 | Recurring fees | Fee and listing-period workflows |
partner:reports:v1 | Reports | Report reads, metrics, and exports |
partner:statement-layouts:v1 | Layouts | Read, create, assign, and remove layouts |
partner:statements:v1 | Statements | Manage, publish, and export statements |
partner:team-deletion:v1 | Team deletion | Delete managed teams and read operations |
partner:team-members:v1 | Members | Read, invite, update, and remove members |
partner:webhooks:v1 | Webhooks | Subscriptions, deliveries, tests, rotation, and replay |
Current early-access domain bundles include destructive operations supported by their domain. Credential management, self-service, internal, demo, and legacy routes remain unavailable to partner API keys.
Authentication expands stored bundle names using the current catalog, so a catalog update applies without replacing an existing key.
GET /api-tokens/permission-bundles returns the assignable API-token catalog.
Each entry contains the stable name, display title, display description,
and expanded permissions. Use this endpoint to render token bundle selectors
instead of keeping a separate client-side list. It uses the same catalog shape
as GET /team/permission-bundles for human roles.
Separate Recording From Money Movement
| Permission or bundle | Effect |
|---|---|
partner:payments:v1 | Records eligible payments and payouts without ACH execution |
partner:ach-payments:v1 | Adds ACH setup and execution capabilities |
transactions:mark-paid | Records an expense payment with provider: null |
statements:record-payout | Records an owner or manager payout without dispatch |
ach-payment-methods:write | Submits an owner or vendor ACH payment method |
ach-payments:execute | Executes, cancels, or unlinks a Ramp payment attempt |
A restricted partner key must combine partner:payments:v1 and
partner:ach-payments:v1 to move money. provider: "ramp" requires the
applicable recording permission and ach-payments:execute before VRPlatform
reads provider state or queues work.
Implementation Checklist
- Load role and primitive-permission catalogs from the API.
- Present one of Team Admin, Standard Member, Operations, or Read Only.
- Keep partner administration, ACH, and managed-team reach independent.
- Save complete replacement arrays, including intentional empty arrays.
- Re-read
GET /meafter the selected user's own access changes. - Gate every action from effective primitive permissions.
- Treat the final API response as authoritative under concurrent changes.
