> ## Documentation Index
> Fetch the complete documentation index at: https://developer.findity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting started

Set up a customer organisation from scratch using the Admin API — from creating the organisation 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 |

> [!WARNING]
>
> A new version of the Admin API (v1) is being rolled out gradually alongside the existing version. As a result, the
> Admin API currently spans two hosts — the legacy admin host and the v1 admin host — with endpoints migrating to v1
> over time. The base URLs and required headers below apply to both.

## Prerequisites

1. Complete [Authentication](/docs/accessing) 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

| 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 | `https://stage-expense.findity.com/api/admin` |
| v1 admin | `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. |

```sh cURL theme={"system"}
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 JSON theme={"system"}
{
  "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
  }
}
```

> [!NOTE]
>
> 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/`

> [!WARNING]
>
> 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

| 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. |

```sh cURL theme={"system"}
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 JSON theme={"system"}
{
  "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. |

```sh cURL theme={"system"}
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 JSON theme={"system"}
{
  "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`

> [!NOTE]
>
> **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

| 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. |

```sh cURL theme={"system"}
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 JSON theme={"system"}
{
  "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`. |

> [!NOTE]
>
> \### With `sendInvitationMail=true`, an email is sent immediately. Use `false` during initial testing.

```sh cURL theme={"system"}
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": "jane.smith@acme.com",
        "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 JSON theme={"system"}
{
  "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/`

> [!WARNING]
>
> **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`. |

> [!NOTE]
>
> 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.

```sh cURL theme={"system"}
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 JSON theme={"system"}
{
  "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 JSON theme={"system"}
{ "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

> **[Organizations](/docs/admin-api-organizations)**
>
> Manage organization settings, lookup, and report counters.

> **[Dimensions](/docs/admin-api-dimensions)**
>
> Configure dimension fields and manage value lists in depth.

> **[Users](/docs/admin-api-users)**
>
> Add, update, and remove employees from an organization.

> **[Chart of accounts](/docs/admin-api-charts-of-accounts)**
>
> Set up and maintain account codes for expense categorization.

> **[Approval structures](/docs/admin-api-approval-structures)**
>
> Define approval workflows and routing rules across departments and dimensions.

> **[Expense API — Getting started](/docs/getting-started-with-expense-api)**
>
> Start working with expense reports once provisioning is complete.
