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.

StepActionDepends on
1Create a customer organizationNone
2Configure dimension fieldsOrganization
3Add dimension valuesDimension fields
4Set up chart of accountsOrganization
5Add usersOrganization
6Create approval structureOrganization, 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

  1. Complete Authentication and obtain an admin-scoped Bearer token.
  2. Decide on an externalSourceId for the organization — your own identifier you'll use to address it across syncs (e.g. org-acme-123).
  3. 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

ConceptDescription
OrganizationThe customer entity. Holds users, dimensions, accounts, and settings. Addressed by externalSourceId on most endpoints.
Template organizationA pre-configured organization whose settings are copied into the new one at creation time. Identified by an internal Findity id.
DimensionA custom field on expenses or expense reports that maps to your accounting structure (e.g. cost center, project).
Dimension valueOne selectable option on a list-type dimension (e.g. Marketing on a Cost center dimension).
Chart of accounts entryAn account code and name used to categorize expenses for financial reporting.
ApproverA 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.

SurfaceStage 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
OperationMethodEndpoint
Create or update an organizationPOST/organizations/externalid/{externalId}/
Configure dimension fieldsPUT/organizations/externalid/{externalId}/customdimensions/
Add dimension valuesPUT/organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/
Create a chart-of-accounts entryPOST/organizations/{organizationId}/accounts (v1 surface)
Add or update usersPUT/organizations/externalid/{externalId}/users/
Assign approvers to dimension valuesPUT/organizations/externalid/{externalId}/customdimensions/{definitionExternalId}/list/approvers/

Required headers

Include these on every request:

HeaderValue
Content-Typeapplication/json
AuthorizationBearer {access_token}
X-Findity-ApiVersion3

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

FieldTypeRequiredDescription
settings.templateOrganizationIdstringYesInternal id of the template organization to copy from. Provided by your Findity contact.
classNamestringYescom.findity.consumer.Company for standard customer orgs.
externalSourceIdstringYesYour 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 the id value — 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 include externalSourceId on each dimension. Without it, the dimension is created with externalSourceId: null and cannot be addressed in Step 3.

Request body fields

FieldTypeRequiredDescription
externalSourceIdstringRecommendedYour unique identifier for the dimension. Required in practice to reference the dimension from later steps.
descriptionstringRecommendedDisplay name shown to users (e.g. Cost center).
levelstringRecommendedEXPENSE (per-expense line) or EXPENSE_REPORT (on the report header).
controlTypestringRecommendedLIST_SEARCHABLE or TEXT.
presetLocationstringOptionalNONE (default), EMPLOYEE, DEPARTMENT, or CATEGORY.
userOverridablebooleanOptionalAllow users to change a preset value.
visibleIfNoPresetbooleanOptionalShow 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

ParameterTypeDefaultDescription
clearBeforeUpdatebooleanfalseWhen true, removes all existing values before inserting the new set. Use for a full sync from your ERP.
cascadebooleanfalseWhen true, applies the same values to every sub-organization under the target organization.

Request body fields

FieldTypeRequiredDescription
idstringYesYour unique identifier for this value.
valuestringYesDisplay text shown to users.
sortOrderintegerOptionalPosition in the list. Lower numbers appear first.
startDatestring (ISO 8601)OptionalDate from which this value is available.
endDatestring (ISO 8601)OptionalDate 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 internal organizationId (the 32-character hex id from Step 1's response), not the externalSourceId.

Request body fields

FieldTypeRequiredDescription
namestringYesHuman-readable account name (e.g. Office Supplies).
numberstringYesAccount 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

ParameterTypeDefaultDescription
sendInvitationMailbooleantrueWhen 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:

FieldTypeRequiredDescription
person.externalSourceIdstringYesYour unique identifier for the person.
person.firstName / person.lastName / person.emailstringYesRequired person details.
person.addressobjectRecommendedStreet address, city, postal code, country code.
externalSourceIdstringYesYour unique identifier for the employee record (distinct from person.externalSourceId).
employeeIdstringOptionalDisplay employee number.
organizationalUnitExternalSourceIdstringOptionalThe unit (department) the user belongs to.
titlestringOptionalJob title.
adminbooleanOptionalGrants admin role on the organization. Defaults to false.
⏱️

With sendInvitationMail=true, an email is sent immediately. Use false during 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:

FieldTypeRequiredDescription
personExternalSourceIdstringYesThe externalSourceId of the person who should approve. Use the value you set in Step 5 (here, person-jane-smith).
sortOrderintegerOptionalPosition in the approval chain (0 = first approver, 1 = second). Defaults to 0.
deletebooleanOptionalWhen 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 supplied personExternalSourceId exists, the request returns 400 "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>" }
StatusReasonDescription
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.
400reference-check-errorThe change would break a referential constraint (e.g. removing a value still referenced on a draft expense). Resolve the references and retry.
401Access token is missing, expired, or invalid. Refresh the token and retry.
403The token does not have admin scope for this organization.
404The organization, dimension definition, or template organization isn't found. Confirm the path parameters.
429Rate limit exceeded. Apply exponential backoff.
500Server error. Safe to retry with backoff; if it persists, contact support with the response body.

Next steps