Expense reports

Group expenses into reports, manage report lifecycle, and submit expense reports for approval using the Expense API.

Group expenses into reports, manage the report lifecycle, and submit reports for approval using either dynamic Fields or direct JSON payloads.

Overview

Expense reports collect one or more expense records into a single submission unit. Users typically create a report, add eligible expenses, review totals and required fields, then submit the report for approval.

Report lifecycle

Expense reports move through a lifecycle as users submit them and approvers process them:

Lifecycle stageTypical statusDescription
DraftNEW, NORMALThe user is still creating or editing the report. Expenses can be added or removed if capabilities allow it.
SubmittedAPPROVALThe report has been submitted and is waiting for approval.
Approved / processingAPPROVED, READY_TO_SEND, TRANSFER, SENDThe report has passed approval and is moving toward export or payment.
CompletedSENT, PAIDThe report has been exported, sent, or paid.
RejectedREJECTEDAn approver rejected the report or one or more included expenses. The user may need to edit and resubmit.

Use processStatus to query broad lifecycle groups:

processStatusIncludes
DRAFTDraft reports such as NEW and NORMAL
PROCESSINGSubmitted and in-progress reports such as APPROVAL, APPROVED, READY_TO_SEND, TRANSFER, and SEND
PROCESSEDCompleted reports such as SENT and PAID
REJECTEDRejected reports

API endpoints

OperationMethodEndpoint
List expense reportsGET/v1/expense/expensereports
Get expense reportGET/v1/expense/expensereports/{expenseReportId}
Create report with FieldsPOST/v1/expense/expensereports?format=fields&organizationId={id}
Update report with FieldsPUT/v1/expense/expensereports/{expenseReportId}?format=fields
Create report with JSONPOST/v1/expense/expensereports
Update report with JSONPUT/v1/expense/expensereports/{expenseReportId}
Submit reportPUT/v1/expense/expensereports/{expenseReportId}?action=send
Delete reportDELETE/v1/expense/expensereports/{expenseReportId}
Initialize report fieldsGET/v1/expense/me/organizations/{id}/expensereports/fields

Step 1: List reports

List reports for an organization by processStatus:

curl -X GET "https://stage-api.findity.com/api/v1/expense/expensereports?organizationId={orgId}&processStatus=DRAFT&include=meta.abbreviation,meta.capabilities,expenseRecords" \
  -H "Authorization: Bearer {access_token}"

Use this to build report tabs such as Draft, Submitted, Approved, and Rejected.

Common include values:

IncludeDescription
meta.abbreviationPre-formatted display values for list views
meta.capabilitiesAvailable user actions, such as whether the report can be edited, deleted, or submitted
expenseRecordsIncluded expenses
expenseRecords.meta.abbreviationPre-formatted display values for included expenses
meta.violationsReport-level validation or policy issues
meta.approvalApproval-related metadata

Step 2: Initialize report fields

Use the report fields endpoint when your application renders the report form dynamically:

curl -X GET "https://stage-api.findity.com/api/v1/expense/me/organizations/{orgId}/expensereports/fields" \
  -H "Authorization: Bearer {access_token}"

To edit an existing report, pass the report ID:

curl -X GET "https://stage-api.findity.com/api/v1/expense/me/organizations/{orgId}/expensereports/fields?expenseReportId={expenseReportId}" \
  -H "Authorization: Bearer {access_token}"

The response contains fields such as:

Field propertycontrolTypeDescription
idTEXTReport ID (hidden, system field)
nameTEXTReport name
descriptionMULTI_LINE_TEXTReport description or comment
recipientListRECIPIENT_LISTOptional email recipients
expenseRecordsLISTExpenses included in the report. Usually multi-select.
Custom dimension fieldsLIST or TEXTOrganization-specific report-level dimensions
previewURLURLPreview link for the report, when available
⚠️

Always send the complete fields array when updating report fields — including hidden fields and fields the user did not modify.

Step 3: Add expenses to a report

A report groups expense records by ID. In a Fields-based UI, users typically select expenses through the expenseRecords field. In JSON format, you provide the expense record IDs directly.

To list expenses that can be added to a report, use the canBeAddedToReport filter:

curl -X GET "https://stage-api.findity.com/api/v1/expense/expenses?organizationId={orgId}&filter=canBeAddedToReport&include=meta.abbreviation,meta.capabilities" \
  -H "Authorization: Bearer {access_token}"

JSON example

curl -X POST "https://stage-api.findity.com/api/v1/expense/expensereports" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "organizationId": "ff808181963979e20196397a2098004b",
    "name": "March expenses",
    "comment": "Expenses from March customer visits",
    "expenseRecords": [
      { "id": "expense-record-id-1" },
      { "id": "expense-record-id-2" }
    ]
  }'

Fields example

curl -X POST "https://stage-api.findity.com/api/v1/expense/expensereports?format=fields&organizationId={orgId}" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{ "fields": [...complete report fields array...] }'

Step 4: Manage report lifecycle

Use meta.capabilities to decide which actions to show in your UI. Capabilities may change based on report status, organization settings, and whether the report contains validation errors.

Common capabilities include:

CapabilityDescription
canBeEditedThe report can be edited
canBeDeletedThe report can be deleted
canBeSentInThe report can be submitted
canBeRetractedThe report can be retracted from approval, if supported by the current workflow state
canAddExpensesExpenses can be added to the report
canRemoveExpensesExpenses can be removed from the report

Update a report

Using Fields:

curl -X PUT "https://stage-api.findity.com/api/v1/expense/expensereports/{expenseReportId}?format=fields" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{ "fields": [...complete report fields array...] }'

Using JSON:

curl -X PUT "https://stage-api.findity.com/api/v1/expense/expensereports/{expenseReportId}" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated March expenses",
    "comment": "Updated after review",
    "expenseRecords": [
      { "id": "expense-record-id-1" },
      { "id": "expense-record-id-2" }
    ]
  }'

Delete a draft report

curl -X DELETE "https://stage-api.findity.com/api/v1/expense/expensereports/{expenseReportId}" \
  -H "Authorization: Bearer {access_token}"

Step 5: Submit for approval

Submit the report when it is complete:

curl -X PUT "https://stage-api.findity.com/api/v1/expense/expensereports/{expenseReportId}?action=send" \
  -H "Authorization: Bearer {access_token}"
⚠️

Do not send a request body when using action=send. The API returns 400 BODY_NOT_ALLOWED if the submit request includes a body.

After submission, the report enters the approval workflow configured for the organization. The report status typically changes to APPROVAL, and approvers can review, approve, or reject the included expenses.

💡

Check meta.capabilities.canBeSentIn before showing a submit button. If submission fails, the API may return validation errors that explain which expense or report field must be corrected.

Retract a submitted report

If the workflow state allows it, retract a submitted report from approval:

curl -X PUT "https://stage-api.findity.com/api/v1/expense/expensereports/{expenseReportId}?action=retract" \
  -H "Authorization: Bearer {access_token}"

Only show this action when meta.capabilities.canBeRetracted is true. Retracting a report returns it from the approval flow so the user can make changes before submitting it again.

Best practices

Prefer Fields for report forms

Use Dynamic Fields when users create or edit reports in your application. Report-level custom dimensions, recipient fields, and expense selection rules can vary by organization, and Fields keeps your UI aligned with those settings.

Use processStatus for navigation

Build report tabs using processStatus instead of maintaining your own status grouping. For example, use DRAFT for editable reports, PROCESSING for submitted reports, PROCESSED for completed reports, and REJECTED for rejected reports.

Use meta.abbreviation for list views

meta.abbreviation contains formatted values for dates, amounts, and labels. Use these values in report lists to match Findity's formatting and localization.

Handle rejected reports clearly

When a report is rejected, show the rejection reason and let the user edit the report or included expenses if capabilities allow it. Re-fetch the report fields before editing so you display the latest validation state.