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

# Dynamic fields

Use server-driven field definitions to dynamically render forms for expenses, expense reports, cards, and user settings.

The Findity Expense API uses a **server-driven UI** pattern called Fields. Instead of hardcoding form layouts in your client, you fetch field definitions from the API and render forms dynamically. The server controls which fields to show, in what order, with what validation — and your client renders them.

## Why use Fields

Building expense management forms is complex. Different organizations configure different categories, dimensions, tax rules, and approval flows. The Fields system handles this complexity on the server side so your client stays simple.

**Consistent behavior across platforms** — Every client (iOS, Android, web) renders the same fields in the same order with the same validation. When the server adds a new field or changes visibility rules, all clients pick it up without a code change.

**Organization-specific configuration** — Each organization can have different expense categories, custom dimensions, representation rules, and country-specific per diem logic. The Fields endpoints return exactly the right fields for the current user's organization — you don't need to implement this logic yourself.

**Reduced client-side complexity** — Your client becomes a renderer. The server decides what to show, whether a field is mandatory, and when changing one field should trigger a re-fetch of the field structure. This eliminates hundreds of conditional branches in your client code.

## How Fields work

Every Fields endpoint returns a JSON structure with a `fields` array, optional `meta` (summary, capabilities), and optional `validationErrors`. Each field object describes one form element.

### The field object

| Property | Type | Description |
| - | - | - |
| `property` | `string` | Unique identifier for this field. Use it as the key when sending data back to the server. |
| `name` | `string` | Translated display label. Show this to the user. |
| `controlType` | `string` | Determines which UI component to render. See [Control types](#control-types). |
| `value` | `any` | Current value. Type depends on `controlType` — can be string, number, boolean, array, or null. |
| `visible` | `boolean` | Whether to show this field. Only render fields where `visible` is `true`. |
| `mandatory` | `boolean` | Whether the field is required. |
| `disabled` | `boolean` | Whether the field is read-only. Used in approval flows where fields are shown but not editable. |
| `requiresUpdate` | `boolean` | If `true`, changing this field's value requires a PUT back to the server to get updated field definitions. See [The update cycle](#the-update-cycle). |
| `error` | `string` | Error code for this field, present when validation fails. |
| `errorText` | `string` | Human-readable error message to display under the field. |
| `url` | `string` | For `LIST` and `LIST_SEARCHABLE` fields — the relative URL to fetch selectable values. |
| `data` | `object` | Pre-loaded list item for `LIST` fields, containing `id`, `name`, and optionally `iconUrl` and `section`. Avoids an extra API call to display the current selection. |
| `custom` | `boolean` | `true` if this is a custom dimension field configured by the organization, `false` for standard fields. |
| `scannable` | `boolean` | `true` if this field can be populated by receipt scanning. |
| `allowFutureDate` | `boolean` | For `DATE` and `DATE_TIME` fields — whether to allow dates after today. |
| `fields` | `array` | Nested child fields when `controlType` is `FIELD_GROUP`. |
| `commands` | `array` | Actions the user can perform on a `FIELD_GROUP`, such as clearing a travel route or removing a stop. |
| `deleteCommand` | `object` | For removable field groups (e.g., travel stops in per diem), the command to delete this group. |
| `summary` | `array` | Compact representation of a `FIELD_GROUP`'s content, useful for collapsed views. |
| `numberOfDecimals` | `integer` | For `DOUBLE` fields — the maximum number of decimal places to display. |
| `informationType` | `string` | For `INFORMATION` fields — one of `normal`, `information`, `warning`, `error`, `success`. |
| `dismissible` | `boolean` | For `INFORMATION` fields — whether the user can dismiss the message. |
| `multiSelect` | `boolean` | For `LIST` fields — whether multiple values can be selected. |
| `listItemType` | `string` | For `LIST` fields with `multiSelect=true` — indicates the type of items in the list. |
| `accessorIconUrl` | `string` | URL for an icon indicating access to commands, typically on `FIELD_GROUP` fields. |
| `accessorText` | `string` | Text that can replace all fields in a `FIELD_GROUP`, used as an accessor display. |

### Control types

Map each `controlType` to a UI component in your client:

| controlType | UI component | Value type | Notes |
| - | - | - | - |
| `TEXT` | Single-line text input | `string` | |
| `MULTI_LINE_TEXT` | Multi-line text area | `string` | Used for comments and descriptions. |
| `DOUBLE` | Decimal number input | `number` | Use `numberOfDecimals` to format display. |
| `INTEGER` | Integer number input | `integer` | |
| `DATE` | Date picker | `string` (ISO 8601) | Check `allowFutureDate`. |
| `DATE_TIME` | Date and time picker | `string` (ISO 8601) | Check `allowFutureDate`. |
| `LOCAL_DATE_TIME` | Date and time picker (no timezone) | `string` (`yyyy-MM-dd HH:mm`) | Used in per diem travel routes. Value is local time. |
| `SWITCH` | Toggle / checkbox | `boolean` | |
| `LIST` | Dropdown / picker | `string` (selected ID) | Fetch options from `url`. May have `multiSelect`. |
| `LIST_SEARCHABLE` | Searchable dropdown | `string` (selected ID) | Fetch options from `url` with search support. |
| `CONTENT_HOLDER` | File/image attachment | `string` (content ID) | For receipt images and attachments. |
| `GUEST_LIST` | Guest list editor | `array` of `{name, company}` | Used in entertainment/representation expenses. |
| `MILEAGE_ROUTE` | Route map editor | `array` of `{place, latitude, longitude}` | For mileage expenses. |
| `FIELD_GROUP` | Container / section | `null` | Contains child `fields`. May have `commands`, `summary`, and `deleteCommand`. |
| `INFORMATION` | Info banner / callout | `string` | Display-only. Check `informationType` for styling. |
| `COMMAND` | Action button | `null` | Triggers a server action via `commands` array. |
| `RECIPIENT_LIST` | Email list editor | `array` of `{email}` | For expense report recipients. |
| `URL` | Link / preview | `string` (URL) | For expense report preview links. |

### Hidden and system fields

Many fields in the response have `visible: false`. These are system fields (like `id`, `status`, `reportStatus`) that carry state between the client and server. **Include them in your PUT requests** but do not render them in the UI.

<Warning>
  Always send the complete fields array back to the server on PUT requests — including hidden fields and fields you didn't modify. The server uses the full state to compute the response.
</Warning>

## The update cycle

The Fields system uses a **request-response cycle** to keep the form state consistent. Some fields are interdependent — for example, changing the expense category can change which custom dimensions are visible, or changing a per diem destination triggers recalculation of deduction periods.

### How `requiresUpdate` works

1. **Initialize** — Call `GET` on the fields endpoint to get the initial field structure.
2. **User edits a field** — If the edited field has `requiresUpdate: true`, call `PUT` on the same endpoint with the full fields array (including the updated value).
3. **Server returns updated fields** — The response contains the new field structure. Replace your local state with this response. Fields may have changed visibility, added new options, or updated other values.
4. **Repeat** — Continue until the user saves or submits.

```
┌────────┐          ┌────────┐
│ Client │          │ Server │
└───┬────┘          └───┬────┘
    │  GET /fields      │
    │──────────────────>│
    │  Fields response  │
    │<──────────────────│
    │                   │
    │  User changes a   │
    │  requiresUpdate   │
    │  field            │
    │                   │
    │  PUT /fields      │
    │  (full fields)    │
    │──────────────────>│
    │  Updated fields   │
    │<──────────────────│
    │                   │
    │  User saves       │
    │                   │
    │  POST /expenses   │
    │  or PUT /expenses │
    │──────────────────>│
    │  Saved expense    │
    │<──────────────────│
```

<Info>
  Only call PUT when the user changes a field with `requiresUpdate: true`. For fields without this flag, update the value locally without making an API call.
</Info>

### Commands and actions

`FIELD_GROUP` and `COMMAND` fields can include a `commands` array. Each command has:

| Property | Description |
| - | - |
| `command` | Query string to append to the PUT request URL (e.g., `action=addStop&afterIndex=2`). |
| `text` | Button label to display. |
| `confirmationRequired` | Whether to show a confirmation dialog before executing. |
| `confirmation` | Text for the confirmation dialog. |

To execute a command, send a PUT request with the command's query parameters appended to the fields endpoint URL.

Note: Some fields in user settings may include client-side action hints in the response, but these are not part of the formal Fields schema and should be handled as implementation-specific extensions.

## Rendering fields

Follow these rules when building your field renderer:

1. **Iterate the `fields` array in order** — The server controls field order. Render fields top-to-bottom as they appear.
2. **Check `visible`** — Skip fields where `visible` is `false`, but keep them in state.
3. **Check `disabled`** — Render disabled fields as read-only.
4. **Render by `controlType`** — Map each `controlType` to your platform's UI component.
5. **Handle `FIELD_GROUP` recursively** — A `FIELD_GROUP` contains nested `fields`. Render it as a section or expandable container, then render its children.
6. **Show errors** — If `error` is not null, display `errorText` as inline validation feedback.
7. **Show `INFORMATION` fields** — Render these as banners or callouts styled by `informationType`.
8. **Load list data** — For `LIST` and `LIST_SEARCHABLE` fields, use the `data` property for the initial display. When the user opens the picker, fetch the full list from `url`.

### Handling `summary` on field groups

Some `FIELD_GROUP` fields include a `summary` array — a flat list of key-value pairs that summarize the group's contents. Use this to display a compact preview when the group is collapsed (e.g., showing "Stockholm → Gothenburg, 468 km" for a mileage route).

### Handling `deletable` field groups

In per diem travel routes, intermediate stops are represented as `FIELD_GROUP` fields with `deletable: true` and a `deleteCommand`. Render a delete action on these groups that executes the command via PUT.

## Saving fields

When the user finishes editing:

<Tabs>
  <Tab title="Expenses">
    Use the fields format for creating and updating expenses:

    * **Create**: `POST /expenses?format=fields&organizationId={id}&expenseType={type}` with the fields payload.
    * **Update**: `PUT /expenses/{expenseId}?format=fields` with the fields payload.

    Alternatively, use the standard JSON format (`POST /expenses` or `PUT /expenses/{id}`) if you extract values from the fields into the standard expense object.
  </Tab>

  <Tab title="Expense reports">
    Use the fields format for creating and updating expense reports:

    * **Create**: `POST /expensereports?format=fields&organizationId={id}` with the fields payload.
    * **Update**: `PUT /expensereports/{id}?format=fields` with the fields payload.
  </Tab>

  <Tab title="Cards">
    Card fields are updated using:

    * **Update**: `PUT /me/organizations/{id}/cards/{cardId}/editfields` with the fields payload.
  </Tab>

  <Tab title="User settings">
    User settings are updated using:

    * **Update**: `PUT /me?format=fields` with the fields payload to persist changes.
    * **Transient update**: `PUT /me/settings/fields` with the fields payload for transient updates (adding/removing temporary approvers).
  </Tab>
</Tabs>

### Handling validation errors

When a save fails due to validation, the response may contain:

* **Field-level errors**: Individual fields will have `error` and `errorText` populated. Re-render the form with these errors shown inline.
* **Top-level `validationErrors`**: An array of `{errorText, errorCode, checkType}` objects. `checkType` can be `BLOCKER` (cannot submit), `ERROR` (save issue), or `WARNING` (can still submit).

## Recommended integration order

Integrate the Fields endpoints in this order, starting with the simplest case and building up:

### 1. Receipt expenses (ReceiptVerification)

Start here — this is the most common expense type and has the most straightforward field structure.

1. Call `GET /me/organizations/{id}/expensetypes/ReceiptVerification/fields` to get the field structure.
2. Build your generic field renderer that handles `TEXT`, `DOUBLE`, `DATE`, `LIST`, `SWITCH`, `CONTENT_HOLDER`, and `FIELD_GROUP`.
3. Implement the `requiresUpdate` cycle with `PUT /me/organizations/{id}/expensetypes/ReceiptVerification/fields`.
4. Save the expense with `POST /expenses?format=fields`.

### 2. Mileage expenses (CarSpecification)

Adds the `MILEAGE_ROUTE` control type and the route travel group with commands.

1. Call `GET /me/organizations/{id}/expensetypes/CarSpecification/fields`.
2. Add `MILEAGE_ROUTE` rendering and command handling (clear travel route, round trip toggle).
3. Handle the `FIELD_GROUP` for travel route with its nested distance fields.

### 3. Per diem expenses (SubsistenceAllowance)

The most complex expense type. Adds `LOCAL_DATE_TIME`, dynamic travel stops (addStop/removeStop commands), and food/accommodation deductions.

1. Call `GET /me/organizations/{id}/expensetypes/SubsistenceAllowance/fields`.
2. Add `LOCAL_DATE_TIME` rendering.
3. Implement add/remove stop commands (dynamic `FIELD_GROUP` manipulation).
4. Handle the food and accommodation deduction groups.

### 4. Food benefit expenses (FoodBenefitsSpecification)

A simpler expense type with breakfast/lunch/dinner toggles.

1. Call `GET /me/organizations/{id}/expensetypes/FoodBenefitsSpecification/fields`.
2. No new control types needed — reuses `SWITCH` and `DATE`.

### 5. Expense report fields

Adds `RECIPIENT_LIST`, `URL` (for preview), and multi-select `LIST` (for expense record selection).

1. Call `GET /me/organizations/{id}/expensereports/fields` to initialize.
2. Add `RECIPIENT_LIST` and `URL` rendering.
3. Handle expense record list management.

### 6. Card fields

Read-only card details and editable card settings.

1. Call `GET /me/organizations/{id}/cards/{cardId}/fields` for read-only view.
2. Call `GET /me/organizations/{id}/cards/{cardId}/editfields` for editable view.
3. Save changes with `PUT /me/organizations/{id}/cards/{cardId}/editfields`.

### 7. User settings fields

Personal settings, bank details, experience settings, app settings, notification settings, and temporary approvers.

1. Call `GET /me/settings/fields` to fetch settings.
2. Handle `COMMAND` fields with `clientCommand` (edit email, edit phone, change password).
3. Handle temporary approver management (addTemporaryApprover/removeTemporaryApprover commands).
4. Save with `PUT /me?format=fields` for persistent changes.

### 8. Approval fields

Read-only fields for the approval flow. All fields have `disabled: true`.

1. Call `GET /me/organizations/{id}/approvals/expense/{expenseId}/fields` for single expense approval.
2. Call `GET /me/organizations/{id}/approvals/expensereports/{reportId}/fields` for report approval.
3. Reuse your existing field renderer — the `disabled` property handles the read-only state.

## Fields endpoints reference

| Endpoint | Method | Description |
| - | - | - |
| `/me/organizations/{id}/expensetypes/{type}/fields` | `GET` | Initialize fields for a new or existing expense. Pass `expenseRecordId` to load an existing expense. |
| `/me/organizations/{id}/expensetypes/{type}/fields` | `PUT` | Transient update — send the full fields array when a `requiresUpdate` field changes. |
| `/me/organizations/{id}/expensereports/fields` | `GET` | Initialize fields for a new or existing expense report. Pass `expenseReportId` to load existing. |
| `/me/organizations/{id}/expensereports/fields` | `PUT` | Transient update for expense report fields. |
| `/me/organizations/{id}/approvals/expense/{expenseId}/fields` | `GET` | Get read-only fields for expense approval. |
| `/me/organizations/{id}/approvals/expensereports/{reportId}/fields` | `GET` | Get read-only fields for expense report approval. |
| `/me/organizations/{id}/cards/{cardId}/fields` | `GET` | Get read-only card details in fields format. |
| `/me/organizations/{id}/cards/{cardId}/editfields` | `GET` | Get editable card details in fields format. |
| `/me/organizations/{id}/cards/{cardId}/editfields` | `PUT` | Update card details. |
| `/me/settings/fields` | `GET` | Get user settings in fields format. |
| `/me/settings/fields` | `PUT` | Transient update for user settings (e.g., add/remove temporary approver). |
| `/me?format=fields` | `PUT` | Persist user settings changes. |
| `/me/organizations/{id}/cards/{cardId}/transactions/{transactionId}/fields` | `GET` | Get card transaction details in fields format (read-only). |
