Getting started
Set up a customer organisation from scratch using the Admin API — from creating the organisation to configuring approval workflows.
Getting started
Set up a customer organization from scratch using the Admin API — from creating the organization to configuring approval workflows.
This guide walks you through six sequential steps for provisioning a new customer on Findity: creating the organization, configuring dimension fields and their values, setting up the chart of accounts, adding users, and wiring up an approval structure. By the end you'll have a fully provisioned organization ready to receive expenses.
Overview
The Admin API provisions a customer in a fixed order — later steps depend on resources created earlier. Plan to complete the six steps in sequence.
| Step | Action | Depends on |
|---|---|---|
| 1 | Create a customer organization | None |
| 2 | Configure dimension fields | Organization |
| 3 | Add dimension values | Dimension fields |
| 4 | Set up chart of accounts | Organization |
| 5 | Add users | Organization |
| 6 | Create approval structure | Organization, Users, Dimensions |
The Admin API spans two hosts. Most endpoints (organizations, dimensions, users, approvers) live on the legacy admin host; the chart of accounts endpoint lives on the v1 admin host. The base URLs and required headers below cover both.
Prerequisites
- Complete Authentication and obtain an admin-scoped Bearer token.
- Decide on an
externalSourceIdfor the organization — your own identifier you'll use to address it across syncs (e.g.org-acme-123). - Identify a template organization to provision from. Templates carry default categories, branding, and settings. Your Findity contact can supply the template's internal id.
Key concepts
| Concept | Description |
|---|---|
| Organization | The customer entity. Holds users, dimensions, accounts, and settings. Addressed by externalSourceId on most endpoints. |
| Template organization | A pre-configured organization whose settings are copied into the new one at creation time. Identified by an internal Findity id. |
| Dimension | A custom field on expenses or expense reports that maps to your accounting structure (e.g. cost center, project). |
| Dimension value | One selectable option on a list-type dimension (e.g. Marketing on a Cost center dimension). |
| Chart of accounts entry | An account code and name used to categorize expenses for financial reporting. |
| Approver | A user authorized to approve expense reports. Approvers are assigned to specific dimension values to drive routing. |
API endpoints
The Admin API uses two stage hosts. Examples in this guide use the stage environment — switch to the corresponding production host (expense.findity.com and api.findity.com) only when you're ready to go live.
| Surface | Stage base URL |
|---|---|
| Legacy admin (organizations, dimensions, users, approvers) | https://stage-expense.findity.com/api/admin |
| v1 admin (chart of accounts) | https://stage-api.findity.com/api/v1/admin |
| Operation | Method | Endpoint |
|---|---|---|
| Create or update an organization | POST | /organizations/externalid/{externalId}/ |
| Configure dimension fields | PUT | /organizations/externalid/{externalId}/customdimensions/ |
| Add dimension values | PUT | /organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/ |
| Create a chart-of-accounts entry | POST | /organizations/{organizationId}/accounts (v1 surface) |
| Add or update users | PUT | /organizations/externalid/{externalId}/users/ |
| Assign approvers to dimension values | PUT | /organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/approvers/ |
Required headers
Include these on every request:
| Header | Value |
|---|---|
Content-Type | application/json |
Authorization | Bearer {access_token} |
X-Findity-ApiVersion | 3 |
Step 1 — Create a customer organization
An organization is the top-level entity representing your customer. Create one before configuring dimensions, accounts, or users. The new organization inherits its categories, branding, and settings from a template organization.
POST /organizations/externalid/{externalId}/
The {externalId} in the path is the new organization's externalSourceId — pick it ahead of time and reuse it across all Step 1–6 calls.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
settings.templateOrganizationId | string | Yes | Internal id of the template organization to copy from. Provided by your Findity contact. |
className | string | Yes | com.findity.consumer.Company for standard customer orgs. |
externalSourceId | string | Yes | Your unique identifier for the new organization. Must match the {externalId} in the URL path. |
cURL
curl -X POST \
"https://stage-expense.findity.com/api/admin/organizations/externalid/org-acme-123/" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Findity-ApiVersion: 3" \
-d '{
"settings": {
"templateOrganizationId": "8a5c89b79c9e1024019c9e127e490abc"
},
"className": "com.findity.consumer.Company",
"externalSourceId": "org-acme-123"
}'
Example response
JSON
{
"id": "8a5c8bee9e3a4a24019e3ae1732b008e",
"externalSourceId": "org-acme-123",
"className": "com.findity.consumer.Company",
"name": "Acme Inc.",
"vat": "123456-1234",
"address": { "country": "Sweden", "countryCode": "SE" },
"clientApplicationId": "16200214",
"partnerId": "241f74a3554840eb913a172d24dceb53",
"settings": {
"language": "sv_SE",
"useNewDimensions": true,
"externallyActivated": true
}
}
The response object also contains branding, services, accounting numbers, categories, payment types, and representation types. The example above is abbreviated for readability. Keep theidvalue — Step 4 (chart of accounts) needs it.
Step 2 — Configure dimension fields
Dimension fields define the categories your customer uses to classify expenses — cost centers, projects, departments, clients, legal entities. Configure the fields first, then populate them with values in Step 3.
PUT /organizations/externalid/{externalId}/customdimensions/
Always includeexternalSourceIdon each dimension. Without it, the dimension is created withexternalSourceId: nulland cannot be addressed in Step 3.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
externalSourceId | string | Recommended | Your unique identifier for the dimension. Required in practice to reference the dimension from later steps. |
description | string | Recommended | Display name shown to users (e.g. Cost center). |
level | string | Recommended | EXPENSE (per-expense line) or EXPENSE_REPORT (on the report header). |
controlType | string | Recommended | LIST_SEARCHABLE or TEXT. |
presetLocation | string | Optional | NONE (default), EMPLOYEE, DEPARTMENT, or CATEGORY. |
userOverridable | boolean | Optional | Allow users to change a preset value. |
visibleIfNoPreset | boolean | Optional | Show the field when no preset applies. |
cURL
curl -X PUT \
"https://stage-expense.findity.com/api/admin/organizations/externalid/org-acme-123/customdimensions/" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Findity-ApiVersion: 3" \
-d '[
{
"externalSourceId": "dim-costcenter",
"description": "Cost center",
"level": "EXPENSE",
"controlType": "LIST_SEARCHABLE",
"presetLocation": "EMPLOYEE"
}
]'
Example response
JSON
{
"result": "success",
"description": "custom dimension definition updated",
"dimensions": [
{
"id": "ef529f9d877d4d44a34609e53e5b8226",
"externalSourceId": "dim-costcenter",
"description": "Cost center",
"level": "EXPENSE",
"controlType": "LIST_SEARCHABLE",
"presetLocation": "EMPLOYEE",
"userOverridable": false,
"visibleIfNoPreset": true
}
]
}
Step 3 — Add dimension values
Once a list-type dimension exists, populate it with the specific values users can select. Wrap the values in a top-level "values" array — a bare top-level array is rejected.
PUT /organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/
{definitionExternalId} is the externalSourceId you set on the dimension in Step 2 (here, dim-costcenter).
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
clearBeforeUpdate | boolean | false | When true, removes all existing values before inserting the new set. Use for a full sync from your ERP. |
cascade | boolean | false | When true, applies the same values to every sub-organization under the target organization. |
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Your unique identifier for this value. |
value | string | Yes | Display text shown to users. |
sortOrder | integer | Optional | Position in the list. Lower numbers appear first. |
startDate | string (ISO 8601) | Optional | Date from which this value is available. |
endDate | string (ISO 8601) | Optional | Date after which this value is no longer available. |
cURL
curl -X PUT \
"https://stage-expense.findity.com/api/admin/organizations/externalid/org-acme-123/customdimensions/dim-costcenter/list/?clearBeforeUpdate=false" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Findity-ApiVersion: 3" \
-d '{
"values": [
{ "id": "cc-001", "value": "Marketing", "sortOrder": 1 },
{ "id": "cc-002", "value": "Engineering", "sortOrder": 2 },
{ "id": "cc-003", "value": "Sales", "sortOrder": 3,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-12-31T23:59:59.000Z"
}
]
}'
Example response
JSON
{
"listKey": "CUSTOM_DIMENSIONS_ef529f9d877d4d44a34609e53e5b8226_8a5c8bee9e3a4a24019e3ae1732b008e",
"lastUpdated": "2026-05-22T07:15:54Z"
}
The response returns the internal listKey for the dimension's value list and the timestamp of the update. It does not echo the submitted values — to read them back, call the corresponding GET on the same path.
Step 4 — Set up chart of accounts
The chart of accounts defines the account codes used for expense categorization and financial reporting. Map each account to the ledger codes your customer's accounting system expects.
POST /organizations/{organizationId}/accounts
This step uses the v1 admin host (stage-api.findity.com/api/v1/admin), not the legacy host used by the other steps. The path also takes the internalorganizationId(the 32-character hexidfrom Step 1's response), not theexternalSourceId.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable account name (e.g. Office Supplies). |
number | string | Yes | Account code in your customer's chart of accounts. |
cURL
curl -X POST \
"https://stage-api.findity.com/api/v1/admin/organizations/8a5c8bee9e3a4a24019e3ae1732b008e/accounts" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Office Supplies",
"number": "6300"
}'
Example response (status 201 Created)
JSON
{
"id": "8a5c88f89e4f3dd1019e4f725ab40010",
"meta": null,
"name": "Office Supplies",
"number": "6300"
}
meta is reserved for future use and is currently null on every response.
Step 5 — Add users
Create user accounts for the employees who will submit, review, or approve expenses. The endpoint is an upsert — supply a stable externalSourceId per person to allow re-syncing from your HR system.
PUT /organizations/externalid/{externalId}/users/
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
sendInvitationMail | boolean | true | When true, Findity sends an invitation email to each new user. Set to false during development to avoid emailing test accounts. |
Request body fields
The body is an array of user objects. Key fields:
| Field | Type | Required | Description |
|---|---|---|---|
person.externalSourceId | string | Yes | Your unique identifier for the person. |
person.firstName / person.lastName / person.email | string | Yes | Required person details. |
person.address | object | Recommended | Street address, city, postal code, country code. |
externalSourceId | string | Yes | Your unique identifier for the employee record (distinct from person.externalSourceId). |
employeeId | string | Optional | Display employee number. |
organizationalUnitExternalSourceId | string | Optional | The unit (department) the user belongs to. |
title | string | Optional | Job title. |
admin | boolean | Optional | Grants admin role on the organization. Defaults to false. |
WithsendInvitationMail=true, an email is sent immediately. Usefalseduring initial testing.
cURL
curl -X PUT \
"https://stage-expense.findity.com/api/admin/organizations/externalid/org-acme-123/users/?sendInvitationMail=false" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Findity-ApiVersion: 3" \
-d '[
{
"person": {
"externalSourceId": "person-jane-smith",
"firstName": "Jane",
"lastName": "Smith",
"email": "[email protected]",
"address": {
"street1": "Storgatan 1",
"city": "Stockholm",
"postalCode": "111 23",
"countryCode": "SE"
}
},
"externalSourceId": "emp-jane-smith",
"employeeId": "12345",
"organizationalUnitExternalSourceId": "ou-marketing",
"title": "Marketing manager",
"admin": false
}
]'
Example response
JSON
{
"result": "success",
"description": "users updated",
"ongoingReports": [],
"movedReports": []
}
The response is a status envelope. To read the user back, call GET /organizations/externalid/org-acme-123/users/.
Step 6 — Create approval structure with dimensions
Approvers are assigned to specific dimension values. When a user submits an expense tagged with a value, the report routes automatically to the assigned approver.
PUT /organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/approvers/
Enable approval first. The approval feature must be activated for the organization in the Findity admin UI before this endpoint accepts assignments. This is a one-time manual step per organization.
Request body fields
Top-level shape: { "values": [ { "id": "<list-value-id>", "approvers": [ { ... } ] } ] }.
Each approver object:
| Field | Type | Required | Description |
|---|---|---|---|
personExternalSourceId | string | Yes | The externalSourceId of the person who should approve. Use the value you set in Step 5 (here, person-jane-smith). |
sortOrder | integer | Optional | Position in the approval chain (0 = first approver, 1 = second). Defaults to 0. |
delete | boolean | Optional | When true, removes this approver assignment instead of upserting it. Defaults to false. |
The approver must be a real user on the organization. If no user with the suppliedpersonExternalSourceIdexists, the request returns400 "failed to update custom field list"and no assignment is created.
cURL
curl -X PUT \
"https://stage-expense.findity.com/api/admin/organizations/externalid/org-acme-123/customdimensions/dim-costcenter/list/approvers/" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Findity-ApiVersion: 3" \
-d '{
"values": [
{
"id": "cc-001",
"approvers": [
{ "personExternalSourceId": "person-jane-smith", "sortOrder": 0 }
]
},
{
"id": "cc-002",
"approvers": [
{ "personExternalSourceId": "person-john-doe", "sortOrder": 0 },
{ "personExternalSourceId": "person-carol-park", "sortOrder": 1 }
]
}
]
}'
This assigns Jane Smith as the approver for Marketing expenses, and a two-step chain (John Doe then Carol Park) for Engineering.
Example response
JSON
{
"listKey": "CUSTOM_DIMENSIONS_ef529f9d877d4d44a34609e53e5b8226_8a5c8bee9e3a4a24019e3ae1732b008e",
"lastUpdated": "2026-05-22T07:15:54Z"
}
Same shape as Step 3. To confirm the assignments persisted, call the corresponding GET on the same path:
GET /organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/approvers/
It returns each list value with its approvers array populated, including each approver's personId, personName, personEmail, and personExternalSourceId.
Common integration patterns
Initial customer onboarding. Run Steps 1–6 once per new customer, in order. Pre-stage the dimension definitions and chart of accounts in your provisioning script so each new org starts identically.
Nightly ERP sync. After onboarding, re-run Step 3 (dimension values) with clearBeforeUpdate=true on a schedule to mirror your ERP's current state. Values removed in the ERP are also removed from Findity.
Multi-organization rollouts. Use cascade=true on the Step 3 PUT to push the same value set to every sub-organization under the target. Useful for shared catalogues (cost centers, projects) managed centrally.
Error handling
Findity returns a JSON envelope on errors:
JSON
{ "result": "error", "description": "<human-readable message>", "reason": "<optional machine-readable hint>" }
| Status | Reason | Description |
|---|---|---|
400 | (none) | Invalid JSON body or missing wrapper. Common cause: the Step 3 / Step 6 body wasn't wrapped in { "values": [...] }. |
400 | (none) | Step 6 only — personExternalSourceId does not match a real user on the organization. Confirm the user was created in Step 5. |
400 | (none) | Step 6 only — approval has not been activated for this organization. Activate it in the Findity admin UI, then retry. |
400 | reference-check-error | The change would break a referential constraint (e.g. removing a value still referenced on a draft expense). Resolve the references and retry. |
401 | — | Access token is missing, expired, or invalid. Refresh the token and retry. |
403 | — | The token does not have admin scope for this organization. |
404 | — | The organization, dimension definition, or template organization isn't found. Confirm the path parameters. |
429 | — | Rate limit exceeded. Apply exponential backoff. |
500 | — | Server error. Safe to retry with backoff; if it persists, contact support with the response body. |
Next steps
Manage organization settings, lookup, and report counters.
Configure dimension fields and manage value lists in depth.
Add, update, and remove employees from an organization.
Set up and maintain account codes for expense categorization.
Define approval workflows and routing rules across departments and dimensions.
Start working with expense reports once provisioning is complete.
Updated 3 days ago
