Skip to content

Global Access Users Matrix

This document defines system-wide access control across all modules.

Access is determined in layers, not only roles.


A request is allowed ONLY if all are true:

  1. Company owns the module (Platform Core)
  2. Membership has the module (Auth)
  3. Membership has permission (Auth)
  4. Endpoint rule allows it (Backend)

Matrix A — Module Access Preconditions (CORRECTED)

Section titled “Matrix A — Module Access Preconditions (CORRECTED)”
Package / Add-onModuleCompany Must OwnMembership Must Be GrantedGrantable By
BasicbasicYesYesSA / AD (delegation rules apply)
FinancefinanceYesYesSA / AD (delegation rules apply)
MarketmarketYesYesSA / AD (delegation rules apply)
VenuevenueYesYesSA / AD (delegation rules apply)
AIaiYesYesSA / AD (delegation rules apply)
TouringtouringYesYesSA / AD (delegation rules apply)

ANY role can access ANY module
ONLY IF:
1. company owns it
2. membership is granted it

Roles DO NOT automatically give module access.


RoleCan Manage UsersCan Grant ModulesCan Grant PermissionsCan Buy Add-ons
TENANT_SUPERADMINYesYesYesYes
ADMINYesYes (restricted)Yes (restricted)No
MANAGERLimitedLimitedLimitedNo
USER / SUBMITTERNoNoNoNo

Matrix B — Endpoint / Role / Scope Access

Section titled “Matrix B — Endpoint / Role / Scope Access”

(Original matrix preserved below — interpreted AFTER module access is validated)


This document defines system-wide access control across all modules.

Access is determined in layers, not only roles.


A request is allowed ONLY if all are true:

  1. Company owns the module (Platform Core)
  2. Membership has the module (Auth)
  3. Membership has permission (Auth)
  4. Endpoint rule allows it (Backend)

Matrix A — Package / Module / Membership Access

Section titled “Matrix A — Package / Module / Membership Access”
PackageModuleCompany EntitlementMembership GrantSAADFNMGSU
BasicbasicYesYesYesYesOptionalOptionalOptional
FinancefinanceYesYesYesYesYesOptionalOptional
MarketmarketYesYesYesOptionalNoOptionalNo
VenuevenueYesYesYesOptionalNoOptionalNo
AIaiYesYesYesOptionalNoOptionalNo

Matrix B — Endpoint / Role / Scope Access

Section titled “Matrix B — Endpoint / Role / Scope Access”

(Original Finance matrix preserved below, now interpreted as post-module access layer)


Related docs: README.md (product + onboarding roles) · README_API.md (HTTP auth, x-org, routes) · README_AUTH_API.md (Kisum Auth JWT, platform vs tenant roles) · README_DOCS.md (architecture, §24 role narrative)

This file holds the endpoint × role grid (PL / SA / AD / FN / MG / SU) plus Legend notes tied to src/lib/auth.ts, src/api/bills/[id]/route.ts, and src/lib/income-access.ts. It does not replace the API reference or architecture docs — cross-links above. Canonical HTTP paths: compare with swagger-output.json after route changes.

Code helpers: isPlatformAdmin (platform JWT), isOrganizationSuperAdminRole (tenant SA), isCompanyAdmin (company AD — includes both Auth ADMIN and TENANT_SUPERADMIN mappings to Finance CompanyRole.ADMIN; the SA column below is only TENANT_SUPERADMIN raw role), isCompanyFinance (FN — company membership only; there is no platform globalRole Finance), approver (MG), submitter (SU).


ShorthandMeaningKisum Auth / Finance
PLPlatform staff — JWT globalRole is PLATFORM_SUPERADMIN, PLATFORM_ADMIN, or PLATFORM_MODERATOR.isPlatformAdmin / isGlobalSuperAdminRole
SATenant org superadmincompany_memberships.authCompanyRole === 'TENANT_SUPERADMIN' for that organization.isOrganizationSuperAdminRole
ADCompany admin — Auth company role ADMIN (not the SA raw role). Maps to Finance CompanyRole.ADMIN alongside SA, but AD column = ordinary company admin unless the row is SA-specific.isCompanyAdmin-style checks excluding SA-only powers where the row splits them
FNFinance — company company_memberships.role === 'FINANCE' (organization level). Not a platform JWT role.isCompanyFinance
MGManager — BU APPROVER (and related).isApproverForBU
SUSubmitter — BU SUBMITTER (and invoiceViewScope).isSubmitterForBU

All = all records across system | Own Co = only their company | Own BU = only their business unit(s) | Own = only their own records

= no access / not applicable for that column | Auth = any authenticated user

Internal (non-vendor) API calls often use x-org to select the active organization. Allowed values: Finance Company.id (UUID), or kisumCompanyId when linked — resolved in src/lib/active-company.ts. Policy: src/lib/x-org-route-policy.ts.


#EndpointPLSAADFNMGSUStatus
ADMIN — COMPANIES
1GET /api/admin/companiesAll, full detailOwn Co, full detailOwn Co, full detailAll, full detailOwn Co, limited (own BUs only, no stats)Own Co, limited (own BUs only, no stats)Correct
2POST /api/admin/companiesYesSubmit; platform approvesCorrect
3PUT /api/admin/companiesYesOwn CoCorrect
4DELETE /api/admin/companiesYesDelete; platform approvesCorrect
5GET /api/admin/companies/[id]/kisumAllOwn CoOwn CoOwn CoCorrect
6POST /api/admin/companies/[id]/kisumAllOwn CoOwn CoOwn CoCorrect
7DELETE /api/admin/companies/[id]/kisumAllOwn CoOwn CoOwn CoCorrect
8GET /api/admin/companies/[id]/xeroAllOwn CoOwn CoOwn CoCorrect (excluded)
9POST /api/admin/companies/[id]/xeroAllOwn CoOwn CoOwn CoCorrect (excluded)
10DELETE /api/admin/companies/[id]/xeroAllOwn CoOwn CoOwn CoCorrect (excluded)
ADMIN — BUSINESS UNITS
11GET /api/admin/business-unitsAllOwn Co, all BUsOwn Co, all BUsAllOwn BU(s) onlyOwn BU(s) onlyCorrect
12GET /api/admin/business-units/by-companyAllOwn CoOwn CoAllOwn CoOwn CoCorrect
13POST /api/admin/business-unitsAllOwn CoOwn CoCorrect
14PUT /api/admin/business-unitsAllOwn CoOwn CoCorrect
15DELETE /api/admin/business-unitsAllOwn CoOwn CoCorrect
ADMIN — USERS
16GET /api/admin/usersAllOwn CoOwn CoAll (read-only)Own BU(s)Correct
17POST /api/admin/usersAllOwn CoOwn CoOwn BU (submitters only)Correct
18PUT /api/admin/usersAllOwn CoOwn CoOwn BU (submitters only)Correct
19DELETE /api/admin/usersFull deleteOwn Co/BU removalOwn Co/BU removalOwn BU removal onlyCorrect
20POST /api/admin/users/[id]/reset-passwordYesCorrect
ADMIN — VENDORS
21GET /api/admin/vendorsAllOwn Co invoice-scopedOwn Co invoice-scopedAll invoice-scopedOwn BU invoice-scopedCorrect
22GET /api/admin/vendors/searchAllOwn Co scopedOwn Co scopedAll scopedOwn BU scopedCorrect
23POST /api/admin/vendorsAllOwn CoOwn CoOwn CoCorrect
24GET /api/admin/vendors/[id]AllOwn Co invoice-scopedOwn Co invoice-scopedAll invoice-scopedOwn BU invoice-scopedCorrect
25PUT /api/admin/vendors/[id]AllOwn Co scopedOwn Co scopedOwn Co scopedCorrect
26DELETE /api/admin/vendors/[id]YesCorrect
27GET /api/admin/vendors/[id]/dashboardAllOwn Co invoice-scopedOwn Co invoice-scopedAll invoice-scopedOwn BU invoice-scopedCorrect
28POST /api/admin/vendors/[id]/link-companyAllOwn CoOwn CoCorrect
29PUT /api/admin/vendors/[id]/link-companyAllOwn CoOwn CoCorrect
30DELETE /api/admin/vendors/[id]/link-companyAllOwn CoOwn CoCorrect
31POST /api/admin/vendors/[id]/activate-portalYesYesCorrect
32DELETE /api/admin/vendors/[id]/activate-portalYesCorrect
ADMIN — OTHER
33GET /api/admin/statsGovernance + scoped stats with x-orgOwn CoOwn CoAllOwn BUOwn invoice scopeCorrect
34GET /api/admin/audit-logsAllOwn CoOwn CoAllCorrect
35GET /api/admin/sync-errorsYesCorrect
36GET /api/admin/kisum/statusYesCorrect
37PATCH /api/admin/expense-categories/[id]YesCorrect
37bPOST /api/admin/expense-categoriesYesOwn CoOwn CoCorrect
37cGET /api/admin/customers/searchAllOwn CoOwn CoAllOwn CoOwn CoCorrect
37dPOST /api/admin/income-categoriesYesOwn CoOwn CoCorrect
37e`PATCHPUT /api/admin/income-categories/[id]`YesOwn CoOwn Co
BILLS (expense / AP)
38GET /api/billsOwn CoOwn CoAllOwn BUOwn / Own BU / Own Co (per invoiceViewScope)Correct
39POST /api/billsOwn CoOwn CoOwn Co: create (BU if required)Own BU (managers if no submitters)Own BU (submitter)Correct
40GET /api/bills/[id]Own CoOwn CoAllOwn BUOwn / scoped (per invoiceViewScope)Correct
41PATCH /api/bills/[id]Escalation chain + privileged update (org supreme)Approve, reject, urgent, pay, update (within admin rules)Mark paid, update (privileged on APPROVED/paid)Approve BU, reject, urgent; waterfall updateSubmit, update own / scopedCorrect
42GET /api/bills/[id]/signed-pdfOwn CoOwn CoAllOwn BUOwn / scopedCorrect
43POST /api/bills/[id]/sync-errorsYes (ops)Own Co (canMarkPaid)Own Co (canMarkPaid)Own Co (canMarkPaid)Correct
44POST /api/bills/[id]/xero-align-payment-idsOwn Co (canMarkPaid)Own Co (canMarkPaid)Own Co (canMarkPaid)Correct
45POST /api/bills/[id]/xero-align-and-create-paymentOwn Co (canMarkPaid)Own Co (canMarkPaid)Own Co (canMarkPaid)Correct
46POST /api/bills/[id]/xero-rebuild-local-masterOwn Co (canMarkPaid)Own Co (canMarkPaid)Own Co (canMarkPaid)Correct
47POST /api/bills/moved-mergeYes (internal bearer)Correct
INCOME (revenue / AR)
48`GETPOST /api/income`Own CoOwn CoAll
49`GETPATCHDELETE /api/income/[id]`Own CoOwn CoAll
50POST /api/income/[id]/paymentsOwn CoOwn CoAllCorrect
51`PUTDELETE /api/income/[id]/payments/[paymentId]`Own CoOwn CoAll
52GET /api/income/reconcile-xeroOwn CoOwn CoAllCorrect
53GET /api/income-categoriesAllOwn CoOwn CoAllOwn CoOwn CoCorrect
KISUM
54GET /api/kisum/[co]AllOwn CoOwn CoAllOwn CoOwn CoCorrect
55GET /api/kisum/[co]/eventsAllOwn CoOwn CoAllOwn CoOwn CoCorrect
56GET /api/kisum/[co]/events/[ev]AllOwn CoOwn CoAllOwn CoOwn CoCorrect
57GET /api/kisum/[co]/events/[ev]/invoicesAllOwn CoOwn CoAllOwn CoOwn CoCorrect
58GET /api/kisum/[co]/events/[ev]/invoices/highlightsAllOwn CoOwn CoAllOwn CoOwn CoCorrect
59GET /api/kisum/[co]/events/[ev]/invoices/[inv]AllOwn CoOwn CoAllOwn CoOwn CoCorrect
60GET /api/kisum/[co]/events/[ev]/income/highlightAllOwn CoOwn CoAllOwn CoOwn CoCorrect
61GET /api/kisum/[co]/events/[ev]/income/summaryAllOwn CoOwn CoAllOwn CoOwn CoCorrect
62GET /api/kisum/event-expense/find-by-event/[id]AllOwn CoOwn CoAllOwn CoOwn CoCorrect
63GET /api/kisum/expense-categoriesAllOwn CoOwn CoAllOwn CoOwn CoCorrect
NOTIFICATIONS
64GET /api/notificationsOwnOwnOwnOwnOwnOwnCorrect
65PATCH /api/notificationsOwnOwnOwnOwnOwnOwnCorrect
FILES & UPLOADS
66POST /api/uploadOwn Co/BUOwn Co/BUOwn Co/BUOwn Co/BUOwn Co/BUCorrect
67POST /api/upload/payment-slipYes (ops)Own Co (canMarkPaid)Own Co (canMarkPaid)Own Co (canMarkPaid)Correct
68POST /api/files/aiYesYesYesYesYesYes (membership)Correct
69GET /api/files/[id]/signed-urlOwn CoOwn CoAllOwn BUOwn / scopedCorrect
DASHBOARD & EXCHANGE
70GET /api/dashboard/convertOwn CoOwn CoAllOwn BUOwn invoice scopeCorrect
71GET /api/exchange-rates/convertAuthAuthAuthAuthAuthAuthCorrect
72POST /api/exchange-rates/convert-batchAuthAuthAuthAuthAuthAuthCorrect
EXPENSE CATEGORIES
73GET /api/expense-categoriesAllOwn CoOwn CoAllOwn CoOwn CoCorrect
COMPANIES (non-admin)
74GET /api/companies/[id]/kisum-linkOwn CoOwn CoAllOwn CoOwn CoCorrect
XERO (excluded from security fixes)
75GET /api/xero/connectOwn CoOwn CoOwn CoCorrect
76GET /api/xero/callbackAuthAuthAuthAuthAuthAuthCorrect (excluded)
77GET /api/xero/tenantsOwn CoOwn CoOwn CoCorrect
78PUT /api/xero/tenantsOwn CoOwn CoOwn CoCorrect
79POST /api/xero/syncOwn CoOwn CoOwn CoCorrect
80GET /api/xero/syncPublicPublicPublicPublicPublicPublicCorrect
81GET /api/xero/currenciesAuthAuthAuthAuthAuthAuthCorrect (excluded)
82GET /api/xero/bank-accountsAuthAuthAuthAuthAuthAuthCorrect (excluded)
83GET /api/xero/liability-accountsAuthAuthAuthAuthAuthAuthCorrect (excluded)
84GET /api/xero/revenue-accountsAuthAuthAuthAuthAuthAuthCorrect (excluded)
85GET /api/xero/tax-ratesAuthAuthAuthAuthAuthAuthCorrect (excluded)
86GET /api/xero/expense-accounts (legacy: /api/xero/accounts)AuthAuthAuthAuthAuthAuthCorrect (excluded)
87GET /api/xero/expense-accounts/cached (legacy: /api/xero/accounts/cached)AuthAuthAuthAuthAuthAuthCorrect (excluded)
88`GETPOST /api/xero/import-from-xero`AuthAuthAuthAuthAuthAuth
89`GETPOST /api/xero/sync/cron`AuthAuthAuthAuthAuthAuth
CRON
90POST /api/cron/invoice-remindersCRON_SECRETCorrect
91GET /api/cron/invoice-remindersCRON_SECRETCorrect
AUTH (Finance API)
92GET /api/auth/profileOwnOwnOwnOwnOwnOwnCorrect
AUTH (Kisum Auth service) — not implemented on this API; use Auth base URL
POST /auth/login, POST /auth/refresh, password reset, etc.Public on AuthPublic on AuthPublic on AuthPublic on AuthPublic on AuthPublic on AuthSee README_AUTH_API.md
VENDOR AUTH (public, separate auth domain)
93POST /api/auth/vendor/loginPublicPublicPublicPublicPublicPublicCorrect
94POST /api/auth/vendor/forgot-passwordPublicPublicPublicPublicPublicPublicCorrect
VENDOR PORTAL (vendor JWT required)
95GET /api/vendor/meOwn (vendor)Correct
96PATCH /api/vendor/meOwn (vendor)Correct
97POST /api/vendor/me/passwordOwn (vendor)Correct
98GET /api/vendor/usersVendor SA onlyCorrect
99POST /api/vendor/usersVendor SA onlyCorrect
100PUT /api/vendor/usersVendor SA onlyCorrect
101GET /api/vendor/invoicesOwn vendorCorrect
102POST /api/vendor/invoicesOwn vendorCorrect
103GET /api/vendor/invoices/[id]Own vendorCorrect
104PUT /api/vendor/invoices/[id]Own vendorCorrect
105GET /api/vendor/statsOwn vendorCorrect
106POST /api/vendor/uploadOwn vendorCorrect
DOCS / OPENAPI
107GET /api/docsPublicPublicPublicPublicPublicPublicCorrect
108GET /api/openapiPublicPublicPublicPublicPublicPublicCorrect

  • PL: no tenant bill actions on platform JWT alone.
  • SA: TENANT_SUPERADMIN — completes escalation / full chain in one step where applicable; privileged update on APPROVED/paid (amount locked after APPROVED); override-class actions per src/api/bills/[id]/route.ts.
  • AD: Company admin — approve, reject, urgent, record payment, update per limits / waterfall; not the same as SA escalation supremacy.
  • FN / MG / SU: As in canProvideNextApproval, canMarkPaid, and waterfall rules.

Total: 108 numbered rows (logical endpoints / route groups), plus one Kisum Auth reference row. Verify against swagger-output.json when changing routes.