Roles and Permissions
Who does what in SpendOne, and how an integration expresses it. Read Core Concepts first for the shape: permissions are the closed vocabulary, permission sets bundle them, roles are derived from the bundle.
The three roles
Roles are derived, never assigned. A user's role follows from the permissions in the permission set you give them, so an integration provisions a permission set code and the role falls out of it.
STANDARD
The default: everyone who requests, buys, or approves spend. A STANDARD user can read the catalog, suppliers, cost centers, legal entities and org units; raise and track purchase requests; act on purchase orders; and read their own invoices and subscriptions.
Approving is part of this role, not a permission you switch on. Every user can act on an approval task assigned to them. Who gets assigned one is a separate question, answered by the approval rules and the org-unit leadership, not by a permission. The can_approve catalog entry still exists so stored permission sets keep validating, but it grants nothing the role does not already give, and it is hidden from the catalog endpoint because a toggle for it would be a lie.
Every STANDARD user also manages their own vacation substitution, which is what keeps approvals moving while they are away.
ACCOUNTANT
Finance. This is the role with the reach over other people's spend: read and write on every invoice in the tenant, the invoice workflow and its substeps, accountant tasks, the accounting export, journal entries and their lines, the chart of accounts, tax mappings, payment methods, subscriptions, the inbound-attachment queue, the AirPlus card data, and the audit log.
Note the asymmetry with ADMIN: since the roles were split, elevated business access lives here, not with the administrator. If your integration reads invoices or audit logs, its service account needs ACCOUNTANT, not ADMIN.
ADMIN
Tool administration. Users and permission sets, the org structure (legal entities, org units, cost centers, groups, tags), suppliers and products, purchase flows, rules, tenant configuration and custom fields, branding, and the data import.
Every route under /admin/… is gated on ADMIN, including the whole data import surface.
The permission catalog
Sixteen permissions, a closed set. An unknown name on a permission set is refused rather than ignored. GET /permissions/catalog returns the ones an administrator may switch on or off, each with its description and the resource/action pairs it grants; the two entries below marked not configurable are excluded from that response but still validate on a stored set.
| Permission | Eligible role | What it allows |
|---|---|---|
can_request | STANDARD | File and manage purchase requests; create products and suppliers along the way |
can_buy | STANDARD | Execute approved purchases: drive purchase-order status, attach invoices |
can_split_cost_centers | STANDARD | Split one purchase across several cost centers. Deliberately separate from can_request |
can_approve | STANDARD | Not configurable. Approving is a baseline capability of every role; see above |
can_assign_approvals | STANDARD | Assign or reassign an approval task to someone else |
can_purchase_on_behalf | STANDARD | Raise a request on behalf of another user |
can_pay_on_invoice | STANDARD | Choose payment on invoice instead of a card |
accounting_handles_invoices | STANDARD | Less a permission than a statement about who does the work: it moves the hand-over point in the invoice workflow for this user's purchases |
can_view_team_tasks | ACCOUNTANT | See tasks assigned to team members, not only one's own |
can_manage_invoices | ACCOUNTANT | Full invoice management |
can_export_accounting | ACCOUNTANT | Run the accounting export and read its results |
can_manage_users | ADMIN | Create, update and deactivate users; manage permission sets |
can_manage_org | ADMIN | Legal entities, org units, cost centers, tags, groups, branding |
can_manage_config | ADMIN | Tenant configuration, rules, transaction-event settings |
can_manage_suppliers | ADMIN | Supplier master data, including block and unblock |
can_view_reports | any | Spend and subscription reports, scoped to the org units the caller leads. Confers no role: granting it cannot escalate anyone |
POST /permissions/check answers a bulk capability question for the calling user, which is the supported way to ask "may I" without replaying the table above in your own code.
Two things that are not permissions
Org-unit leadership. The leader (and optional deputy) of an organizational unit is who the approval engine routes that unit's spend to. It is set on the unit, not on the user, and it is independent of role: a STANDARD user leads their department and approves for it. In the users import this is the Leads Org Unit Code column; over the API it is leader_id / deputy_leader_id on the org unit.
The reporting manager. manager_code on the user is the org chart: who reports to whom. It is not an approval route. The two are set separately and mean different things; conflating them is the most common modeling mistake in a first integration.
What an integration should provision
Assign a permission set code, not a role and not a permission list:
curl -X POST https://api.spendone.tech/api/v1/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "anna.becker@example.com",
"first_name": "Anna",
"last_name": "Becker",
"external_id": "E1001",
"permission_set_code": "standard"
}'
The bulk import does the same thing through the Permission Profile column, matched by the set's name. Either way the set is the unit of change: adjust the set once and every user holding it moves with it, rather than re-granting permissions per person.
For the full provisioning flow, see Push users and permissions.