Core Concepts
The object model your integration writes into. Everything else in SpendOne hangs off these five things and the lifecycle that runs through them.
Tenant
└── Legal entity invoices, books and cards belong to one
└── Organizational unit the org chart; has a leader, who approves
├── Cost center what spend is charged to
└── Users the people, with a permission set
Tenant
One customer, one tenant, one isolated database schema. There is no cross-tenant call and no tenant parameter on any endpoint: the tenant is taken from the signed tenant_id claim on the bearer token, so one credential belongs to exactly one tenant (see API Basics).
Legal entity
The company that actually buys, is invoiced, and books the spend. A tenant has one or more; exactly one is marked primary.
An entity carries its own tax ID, address and default currency (ISO 4217), and it is the level at which several things are decided:
- Which chart of accounts applies. An entity either uses the tenant-wide chart or enables its own (
PUT/DELETE /legal-entities/{code}/custom-chart-of-accounts). - Which purchase flows apply. Same pattern (
PUT/DELETE /legal-entities/{code}/custom-purchase-flows). - Which card account a virtual card bills. The AirPlus procurement account is configured on the entity, and it is resolved from the purchase's entity, not the tenant's primary one. An entity with no account configured cannot issue cards.
GET /legal-entities, POST /legal-entities, PUT /legal-entities/{code}, PATCH /legal-entities/{code}/deactivate.
Organizational unit
Your org chart, as a tree. Each unit belongs to one legal entity, may have a parent (leave it empty for a root unit; cycles are rejected), and carries:
- a leader and an optional deputy leader: the people the approval engine routes to for spend originating in that unit;
- members: the users that belong to it;
- one or more cost centers.
GET /organizational-units, GET /organizational-units/root, GET /organizational-units/{code}/children, GET /organizational-units/{code}/hierarchy, POST /organizational-units, PUT /organizational-units/{code}, PATCH /organizational-units/{code}/deactivate. Membership: POST/DELETE /organizational-units/{code}/members/{user_code}, GET /organizational-units/{code}/members.
Create parents before children. A create naming a parent code that does not exist yet is rejected.
Cost center
Code, name, and the org units it belongs to. Cost centers are what spend is charged to, so they drive three separate things: approval routing, the booking proposal that becomes a journal entry, and the reference data sent with every virtual card. A card issued against an order with no cost center reconciles against nothing.
GET /cost-centers, GET /cost-centers/{code}, POST /cost-centers, PUT /cost-centers/{code}, PATCH /cost-centers/{code}/deactivate.
Users
A person in the tenant. Not "accounts": a user is the authorization record for who they are, what they may do, and where in the organization they sit. Authentication is separate and lives with the identity provider (see SSO and user provisioning).
The fields an integration usually cares about:
| Field | Meaning |
|---|---|
code | The stable SpendOne identifier, used in every path and filter |
external_id | Your identifier for the person, the HR employee ID. Written by the users import, and overwritten by the employee_id claim on SSO login when the IdP sends one |
email | Login email; unique, stored lowercased |
manager_code | The reporting manager. Distinct from org-unit leadership: a manager is the org chart, a leader is who approves |
organizational_units | The units the user belongs to |
permission_set_code | The permission set assigned to them |
permissions, roles | The resolved capabilities and roles that set grants |
GET /users, GET /users/{id}, GET /users/by-external/{external_id}, GET /users/by-role/{role}, POST /users, PUT /users/{id}, PATCH /users/{id}/deactivate. Offboarding is a deactivate, never a delete: a deleted user would break the audit trail and the approval history that references them.
Roles, permissions and permission sets
Three layers, and only the middle one is a closed set you can rely on.
Permissions are the closed vocabulary of 16 capabilities (can_request, can_approve, can_manage_invoices, …). An unknown name is refused, not 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; POST /permissions/check answers a bulk capability question for the calling user.
Permission sets are named bundles of permissions. A user holds exactly one. A set can be marked the default for new users, and is deactivated rather than deleted.
GET /permission-sets, POST /permission-sets, PUT /permission-sets/{code}, PATCH /permission-sets/{code}/activate, PATCH /permission-sets/{code}/deactivate, POST /permission-sets/{code}/set-default.
Roles (STANDARD, ACCOUNTANT, ADMIN) are derived from the permissions in the set, never assigned directly. role on the create and update payloads is accepted for backward compatibility and ignored. A set can grant more than one role. Which role each permission implies, and what each role does day to day, is in Roles and Permissions.
Groups
A named collection of users, used to address notifications and to restrict which purchase flows a person may use. Four kinds, and only two are creatable: static holds an explicit member list, dynamic computes its members from a rule, and the read-only role and ou kinds are derived from roles and org units. Kind is fixed at creation.
GET /groups, POST /groups, GET /groups/{code}/members, PUT /groups/{code}/members, POST/DELETE /groups/{code}/members/{user_code}, GET /groups/by-user/{user_code}.
Purchase flows and rules
A purchase flow bundles the wizard a requester sees, the approval rule that applies, the payment methods offered and the accounting handling, scoped to one legal entity and optionally restricted to an audience of groups. GET /purchase-flows, GET /purchase-flows/available (the ones the calling user may use), POST /purchase-flows, PUT /purchase-flows/{code}.
Rules are the configurable engine behind approvals and automation: thresholds, routing, triggers. GET /rules, POST /rules, POST /rules/simulate (dry-run a rule against real data before saving it), GET /rules/executions.
Data export configuration
Every approved invoice ends as a journal entry, and the journal entry leaves the platform through the tenant's export method. One method per tenant, read with GET /csv-export/method and set with PUT /csv-export/method:
| Method | What it produces |
|---|---|
CSV | A CSV file shaped by a configurable export profile |
EMAIL | The export file delivered by email |
SAP | An SAP-shaped file, fetched from the export job |
DATEV | A booking proposal submitted to DATEV Unternehmen Online |
DATEV_REWE | A document upload to DATEV Unternehmen Online followed by a Rechnungswesen booking entry |
POST /fi-export/jobs reads the tenant's method and routes to it, so the job
flow is the same call whichever of the five a tenant runs.
Three pieces of configuration have to exist before the first export:
- The chart of accounts: tenant-wide, or per legal entity where the entity enables its own.
GET /accounts,POST /accounts/import. - Tax-code mappings,
GET /tax-mappings. An invoice carrying an unmapped VAT rate fails the transfer with problem typebooking-tax-code-unmapped;GET /tax-mappings/gapsreports the tuples still missing across unposted bookings. - The export shape: for
CSV, a profile with an ordered field list, a delivery target (S3 or SFTP) and optional lookup tables that translate values on the way out (GET /csv-export/profiles,/csv-export/targets,/csv-export/lookup-tables). ForDATEVandDATEV_REWE, the OAuth connection and the per-entity export configs underGET /datev/exports/configs.
The mechanics of running an export are in Accounting System Integration.
The spend lifecycle
The sequence every piece of spend follows, and the point of the object model above:
A purchase request captures the need against a cost center and a supplier; the approval engine resolves who must approve it from the rules, the amount and the org unit's leader; an approved request becomes a purchase order; receipt is recorded against the order; the supplier's invoice arrives and is extracted, matched, tax-validated and booked; the booking becomes a journal entry; the export method carries it into the customer's ledger; payment settles it, and reconciliation checks that every order has an invoice and every card transaction has a document behind it. Every step writes an audit-log entry.
Stage by stage, with the entity each one creates and the endpoints that fire: The Spend Lifecycle.