Fields - Mileage expenses
Create and manage mileage expense claims using the dynamic Fields system in the Expense API.
Create mileage expense claims (car specifications) using the dynamic Fields system. This guide covers initializing fields, handling the route and vehicle type selection, managing trip details, and saving mileage expenses.
Overview
Mileage expenses use the CarSpecification expense type. They allow users to claim reimbursement for business travel based on distance driven, vehicle type, and optional extras like passengers, road tolls, and trailer usage.
The Fields system handles the complexity of mileage calculations — including country-specific reimbursement rates, vehicle type multipliers, and distance computation from routes. Your client renders the fields and lets the server do the math.
Key concepts
| Concept | Description |
|---|---|
| Route | An ordered list of places (with coordinates) that defines the travel path. The server calculates distance automatically. |
| Vehicle type | The type of vehicle used (e.g., private car, company car, motorcycle). Affects reimbursement rates. |
| Round trip | A toggle that doubles the calculated distance. |
| Manual distance | Allows the user to override the server-calculated distance with a manually entered value. |
| Trip details | Optional extras: passengers, road tolls, gravel distance, trailer, caravan, etc. |
| Commuting | A variant of mileage for commuting expenses, with year/month/day selection instead of route-based travel. |
API endpoints
All mileage field operations use the standard Fields endpoints with expenseType=CarSpecification:
| Operation | Method | Endpoint |
|---|---|---|
| Initialize fields | GET | /v1/expense/me/organizations/{id}/expensetypes/CarSpecification/fields |
| Update fields | PUT | /v1/expense/me/organizations/{id}/expensetypes/CarSpecification/fields |
| Create expense | POST | /v1/expense/expenses?format=fields&organizationId={id}&expenseType=CarSpecification |
| Update expense | PUT | /v1/expense/expenses/{expenseId}?format=fields |
| Get car types | GET | /v1/expense/me/organizations/{id}/categories/{categoryId}/cartypes |
| Get categories | GET | /v1/expense/me/organizations/{id}/expensetypes/CarSpecification/categories |
Step 1: Initialize fields
Fetch the field structure for a new mileage expense:
curl -X GET "https://stage-api.findity.com/api/v1/expense/me/organizations/{orgId}/expensetypes/CarSpecification/fields" \
-H "Authorization: Bearer {access_token}"To load an existing mileage expense for editing, pass the expense record ID:
curl -X GET "https://stage-api.findity.com/api/v1/expense/me/organizations/{orgId}/expensetypes/CarSpecification/fields?expenseRecordId={expenseId}" \
-H "Authorization: Bearer {access_token}"Field structure overview
The response contains these key fields:
| Field property | controlType | Description |
|---|---|---|
id | TEXT | Expense ID (hidden, system field) |
categoryId | LIST | Mileage category — requiresUpdate: true |
verification.comment | MULTI_LINE_TEXT | User comment |
expenseReportId | LIST | Assign to an expense report |
verification.travelDate | DATE_TIME | Date and time of travel |
verification.destination | TEXT | Auto-generated from route (hidden, read-only) |
verification.carType | LIST | Vehicle type — requiresUpdate: true |
verification.travelRoute | FIELD_GROUP | Route container with nested fields |
verification.travelTime | TEXT | Travel time (hidden, system field) |
| Custom dimension fields | LIST | Organization-specific dimensions (e.g., cost center, project) |
Step 2: Handle the route
The travel route is a FIELD_GROUP containing several nested fields:
| Nested field | controlType | Description |
|---|---|---|
verification.manualDistance | SWITCH | Toggle manual distance entry — requiresUpdate: true |
verification.route | MILEAGE_ROUTE | Array of route points with place, latitude, longitude |
verification.distance | DOUBLE | Calculated distance (or manual entry when manualDistance is true) |
verification.roundTrip | SWITCH | Doubles the distance — requiresUpdate: true |
verification.numberOfPassengers | INTEGER | Number of extra passengers |
verification.tollCost | DOUBLE | Road toll amount |
verification.distanceOnGravel | DOUBLE | Distance driven on gravel roads |
verification.distanceInTransport | DOUBLE | Distance with vehicle on transport |
verification.distanceWithTrailer | DOUBLE | Distance with trailer attached |
verification.distanceWithCaravan | DOUBLE | Distance with caravan attached |
verification.distanceWithHeavyCaravan | DOUBLE | Distance with heavy caravan |
verification.distanceWithDog | DOUBLE | Distance with dog in vehicle |
verification.travelTime | TEXT | Calculated travel time — requiresUpdate: true |
Not all trip detail fields are visible by default. Their visibility depends on the organization's configuration and country-specific rules. Only render fields where
visible: true.
Route data format
The MILEAGE_ROUTE field holds an array of waypoints:
[
{ "place": "Stockholm, Sweden", "latitude": "59.3293481", "longitude": "18.0682306" },
{ "place": "Gothenburg, Sweden", "latitude": "57.7086375", "longitude": "11.9747055" }
]The first entry is the origin, the last is the destination, and any entries in between are via points. When the route changes and requiresUpdate is true, the server recalculates the distance and generates a map image.
Adding via points
Routes can include intermediate stops. A route with two via points:
[
{ "place": "Ludvika", "latitude": "60.1523510", "longitude": "15.1919879" },
{ "place": "Falun", "latitude": "60.609036", "longitude": "15.629638" },
{ "place": "Borlänge", "latitude": "60.489796", "longitude": "15.434664" },
{ "place": "Stockholm", "latitude": "59.3293481", "longitude": "18.0682306" }
]Route commands
The travel route field group includes a commands array for clearing the route:
{
"commands": [
{
"text": "Clear travel route",
"confirmationRequired": true,
"confirmation": "Are you sure you want to clear travel routes?",
"command": "action=removeTravelRoute"
}
]
}Execute by appending the command to the PUT URL:
PUT /v1/expense/me/organizations/{id}/expensetypes/CarSpecification/fields?action=removeTravelRoute
Map image
After a route update, the server generates a map image. The URL is stored in the hidden field virtual.mileageMap:
{ "property": "virtual.mileageMap", "visible": false, "value": "https://expense.findity.com/api/resources/ff8080818cd9867f..." },
{ "property": "virtual.mileageMapChecksum", "visible": false, "value": "236c7fd6d8462091c3f36a33756cfa44b386433b" }Use this URL to display a visual route preview in your UI. The server also provides a virtual.mileageMapChecksum field for cache validation. Both fields are hidden and read-only.
Step 3: Vehicle type and category
Both the category (categoryId) and vehicle type (verification.carType) have requiresUpdate: true. Changing either triggers a server round-trip that may update reimbursement calculations and visible fields.
Fetching vehicle types
Vehicle types are scoped to the selected category:
GET /v1/expense/me/organizations/{id}/categories/{categoryId}/cartypes
Common vehicle types include:
| Value | Description |
|---|---|
PRIVATE_CAR | Private car |
COMPANY_CAR | Company car |
COMPANY_CAR_DIESEL | Company car (diesel) |
COMPANY_CAR_ELECTRICITY | Company car (electric) |
MOTOR_CYCLE | Motorcycle |
MOTOR_CYCLE_GT_125CC | Motorcycle > 125cc |
MOTOR_CYCLE_LTE_125CC | Motorcycle ≤ 125cc |
MOPED | Moped |
CYCLE_OR_WALKING | Bicycle or walking |
PUBLIC_TRANSPORTATION | Public transportation |
The full list of vehicle types depends on the organization's country and configuration. Always fetch from the API rather than hardcoding values.
Step 4: The update cycle
Mileage expenses have several fields with requiresUpdate: true. When the user changes any of these, send the full fields array back to the server:
PUT /v1/expense/me/organizations/{id}/expensetypes/CarSpecification/fields
Fields that trigger an update:
| Field | What changes on update |
|---|---|
categoryId | Visible fields, vehicle type options, reimbursement rates |
verification.carType | Reimbursement rate, trip detail visibility |
verification.manualDistance | Toggles between calculated and manual distance input |
verification.roundTrip | Doubles or halves the distance |
verification.route | Recalculates distance and generates a new map |
verification.fuelType | Updates toll cost calculations (where applicable) |
verification.bompeng | Updates road toll data (Norwegian organizations) |
Example update request
curl -X PUT "https://stage-api.findity.com/api/v1/expense/me/organizations/{orgId}/expensetypes/CarSpecification/fields" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"fields": [
{ "property": "id", "value": null },
{ "property": "categoryId", "value": "b219079277d14c77a0c85497504cf90b" },
{ "property": "verification.carType", "value": "PRIVATE_CAR" },
{ "property": "verification.travelDate", "value": "2024-01-05T12:46:11Z" },
{ "property": "verification.travelRoute", "fields": [
{ "property": "verification.manualDistance", "value": false },
{ "property": "verification.route", "value": [
{ "place": "Stockholm, Sweden", "latitude": "59.3293481", "longitude": "18.0682306" },
{ "place": "Ludvika, Sweden", "latitude": "60.1523510", "longitude": "15.1919879" }
]},
{ "property": "verification.distance", "value": 434 },
{ "property": "verification.roundTrip", "value": false }
]}
]
}'Always send the complete fields array — including hidden fields and fields you didn't modify. The server uses the full state to compute the response.
Step 5: Save the expense
Once the user is finished, save the mileage expense:
Using fields format
POST /v1/expense/expenses?format=fields&organizationId={id}&expenseType=CarSpecification
Send the full fields payload as the request body. The server validates all fields and returns the created expense.
Using standard JSON format
Alternatively, extract values from the fields and use the standard expense format:
curl -X POST "https://stage-api.findity.com/api/v1/expense/expenses" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"organizationId": "ff808181963979e20196397a2098004b",
"categoryId": "b2d50112c6fa4411b75208c23c21b323",
"verification": {
"type": "CarSpecification",
"carType": "PRIVATE_CAR",
"travelDate": "2024-01-31T23:00:00Z",
"description": "Trip to Gothenburg",
"manualDistance": false,
"roundTrip": false,
"distance": 468,
"distanceUnit": "KM",
"route": [
{ "place": "Stockholm, Sweden", "latitude": "59.3293481", "longitude": "18.0682306" },
{ "place": "Gothenburg, Sweden", "latitude": "57.7086375", "longitude": "11.9747055" }
],
"passengers": [],
"tripDetails": {
"carRegistrationNumber": "AB12345",
"numberOfPassengers": 2,
"tollCost": 10,
"distanceOnGravel": 0,
"distanceInTransport": 0,
"distanceWithTrailer": 0,
"distanceWithCaravan": 0,
"distanceWithHeavyCaravan": 0,
"distanceWithDog": 0
}
}
}'Example response
{
"id": "67c18882083149599859054bcebb4ca0",
"organizationId": "ff808181963979e20196397a2098004b",
"personId": "ff808181963979e20196397a119f002d",
"status": "NORMAL",
"processStatus": "DRAFT",
"categoryId": "b2d50112c6fa4411b75208c23c21b323",
"reimbursementCurrency": "SEK",
"reimbursementAmount": 2340.00,
"dateCreated": "2024-01-31T10:52:48Z",
"lastUpdated": "2024-01-31T10:52:48Z",
"verification": {
"type": "CarSpecification",
"carType": "PRIVATE_CAR",
"travelDate": "2024-01-31T23:00:00Z",
"description": "Trip to Gothenburg",
"destination": "Stockholm, Sweden - Gothenburg, Sweden",
"distance": 468,
"distanceUnit": "KM",
"manualDistance": false,
"roundTrip": false,
"route": [
{ "place": "Stockholm, Sweden", "latitude": "59.3293481", "longitude": "18.0682306" },
{ "place": "Gothenburg, Sweden", "latitude": "57.7086375", "longitude": "11.9747055" }
],
"passengers": [],
"tripDetails": {
"carRegistrationNumber": "AB12345",
"numberOfPassengers": 2,
"tollCost": 10,
"distanceOnGravel": 0,
"distanceInTransport": 0,
"distanceWithTrailer": 0,
"distanceWithCaravan": 0,
"distanceWithHeavyCaravan": 0,
"distanceWithDog": 0
}
}
}Commuting variant
Some organizations configure mileage categories for commuting. Commuting expenses replace the route-based travel with a year/month/day selection:
| Field | controlType | Description |
|---|---|---|
verification.commuting.year | LIST_SEARCHABLE | Year to report commuting for |
verification.commuting.month | LIST_SEARCHABLE | Month to report — requiresUpdate: true |
verification.commuting.days | LIST_SEARCHABLE | Number of commuting days |
Fetch the available values from these endpoints:
GET /v1/expense/me/organizations/{id}/commuting/years
GET /v1/expense/me/organizations/{id}/commuting/months?year=2025
GET /v1/expense/me/organizations/{id}/commuting/days?year=2025&month=6
The route field group is still present in commuting mode but with a simplified structure — the vehicle type is typically locked (e.g., PRIVATE_CAR with disabled: true).
Named passengers
Some organizations require named passengers instead of just a count. When enabled, the passengers array contains individual entries:
{
"passengers": [
{ "name": "Albert", "distance": 100 },
{ "name": "Herbert", "distance": 200 },
{ "name": "Kyle", "distance": 150 }
]
}Each passenger has a name and the distance they traveled. This is used for per-passenger reimbursement calculations in some countries.
Fleet management integration
Organizations with fleet management integrations can link mileage expenses to tracked vehicle trips:
{
"verification": {
"relatedTrips": [
{ "fleetManagementTripId": "12345678" },
{ "fleetManagementTripId": "12345679" }
]
}
}Fetch available trips from:
GET /v1/expense/me/organizations/{id}/categories/{categoryId}/fleetmanagementtrips
In the fields format, fleet management trips appear as a LIST field with multiSelect: true at verification.fleetManagementTripIds.
Toll cost data
For Norwegian organizations using AutoPASS or similar toll systems, toll cost data can be included:
{
"verification": {
"tollCostFuelType": "HYBRID",
"tollCostData": {
"price": 100,
"discountedPrice": 90,
"returnPrice": 200,
"returnDiscountedPrice": 180
}
}
}The tollCostFuelType affects the toll rate calculation and supports: PETROL, DIESEL, ELECTRIC, HYBRID, and HYDROGEN.
Common integration patterns
Route suggestions with place search
Use the route suggestions endpoint to provide autocomplete when users type a place name:
GET /v1/expense/route/suggestions?place=StocReturns a list of matching places. After the user selects origin and destination, call the directions endpoint to get coordinates and calculated distance:
POST /v1/expense/route/directionsWith a body of [{ "place": "Stockholm" }, { "place": "Gothenburg" }].
Handling manual distance override
When the user toggles verification.manualDistance to true, the verification.distance field becomes editable and the verification.route field is no longer required. Send a PUT to update the fields — the server will adjust field visibility accordingly. When toggled back to false, the distance is recalculated from the route.
Round trip handling
When verification.roundTrip is toggled to true, the server doubles the calculated distance. This is a requiresUpdate field — send a PUT to get the updated distance value. The route itself stays the same; only the distance is doubled.
Rendering the route summary
The travel route FIELD_GROUP includes a summary array for displaying a compact preview:
[
{ "type": "image" },
{ "type": "property_value", "property": "Distance", "value": "468 km" }
]Use the image type to display the map from virtual.mileageMap, and property_value entries to show key metrics like distance.
Error handling
Common errors when working with mileage expenses:
| Status code | Error code | Description |
|---|---|---|
400 | NOT_A_CAR_SPECIFICATION_CATEGORY | The category ID provided is not a mileage category. Fetch categories for CarSpecification expense type. |
400 | INVALID_JSON_BODY | Failed to parse the request body or no known properties received. |
400 | INVALID_JSON_PROPERTY_VALUE | Missing or invalid type on verification — ensure type is set to CarSpecification. |
400 | TOO_FEW_ROUTE_PLACES | Route requires at least 2 places (origin and destination). |
404 | EXPENSE_RECORD_NOT_FOUND | The expense ID does not exist or is not accessible by the current user. |
404 | CATEGORY_NOT_FOUND | The specified category does not exist in the organization. |
404 | FLEET_MANAGEMENT_ACCOUNT_NOT_FOUND | Fleet management account not configured for the organization. |
404 | FLEET_MANAGEMENT_VEHICLE_NOT_FOUND | No vehicle found for the current user in fleet management. |
Next steps
Full reference for the Fields system, control types, and the update cycle
API reference for calculating route directions and distances
Guide for creating receipt-based expenses using Fields
Guide for creating per diem / subsistence allowance expenses
Updated about 4 hours ago
