The Timesheet Reconciliation API lets authorised users create or correct time entries in bulk. You can submit a single correction or a batch of corrections in one request.
This article explains who can use the API, what information each correction needs, the rules that are applied, and how to interpret the results.
Who can use it
To submit timesheet reconciliation corrections you must:
Be a Financial Administrator, and
Be a Timesheet Administrator, and
Have the feature Timesheet Corrections enabled for your organisation, and
Have the feature Timesheet Reconciliation Correction enabled for your organisation.
If any of these conditions is not met, the request is rejected with 403 Forbidden response and no corrections are saved.
What you can do
Submit a single correction – send one correction entry and receive the outcome for that entry.
Submit a batch of corrections – send many correction entries at once and receive a per-row outcome plus an overall summary.
Each entry either creates a new correction or updates an existing one. To update an existing correction, include its Record Id. To create a new correction, leave the Record Id empty (or set it to 0).
Information needed for each correction
Each correction entry is made up of the following fields.
Required
Every entry must include all of the following:
Date – the date the time relates to.
Hours – the number of hours being recorded for the correction.
A way to identify the resource – provide either a Resource Ref or an External Ref.
A way to identify the work – provide at least one of Project Ref, Alternate Project Ref, or Project (name) for the non-project related work such as 'Leave' etc.
Optional
These fields can be supplied to add more detail or to support specific scenarios:
Record Id – the identifier of an existing correction you want to update. To get the Record Id for existing corrections, use the 'Find' end-point to fetch corrections for a date-range. Omit the Record Id to create a new correction.
Resource – the resource (person) name.
Financial Ref – a financial reference associated with the work.
Task – the flex-task the time relates to.
Sub Activity – a more granular activity under the task.
Local Value – a monetary value for the entry, in local currency.
Local Currency Code – the currency for the Local Value.
Notes – free-text notes about the correction.
Validation rules
Corrections are checked in two stages.
1. Basic (entry) checks
These are applied first to every entry:
A Date must be supplied.
Hours must be supplied.
The resource must be identifiable by a Resource Ref or an External Ref.
The work must be identifiable by a Project Ref, an Alternate Project Ref, or a Project name.
RecordId must be greater than or equal to 0.
An entry that fails any of these checks is marked invalid and is not processed further. The reason is returned against that entry.
2. Business checks
Entries that pass the basic checks are then validated against your organisation's data and rules, for example:
The RecordId must exist in the system.
The resource referenced must exist.
The project or work item referenced must exist and be valid for timesheet corrections.
The date must fall within a period that is open for correction (periods that have been locked or prior to Capitalization Lock Date cannot be corrected).
The Project must be of a type or status that the Timesheet Configuration marks as excluded from corrections.
Any supplied currency must be valid.
Entries that fail a business check are marked invalid and the specific reason is returned against the corresponding row. Entries that pass all checks are submitted.
Partial success is supported. When you submit a batch, valid entries are applied even if other entries in the same batch are invalid. You do not need to resubmit the whole batch to fix a single bad row.
Understanding the results
Single correction
The response tells you whether the entry was valid or invalid, and includes any validation messages explaining why an entry was rejected.
Batch of corrections
The response includes an overall summary and a per-row breakdown:
Status – the overall outcome of the batch:
success – every entry was valid and applied.
partial – some entries were valid and applied; others were invalid.
failed – no entries were valid; nothing was applied.
Total count – the number of entries submitted.
Valid count – the number of entries that passed validation and were applied.
Invalid count – the number of entries that failed validation.
Per-row results – for each entry, whether it was valid, and any validation messages.
Correlation Id – a reference for the batch, useful when reviewing or following up on a submission.
Tips for a clean submission
Always include Date and Hours on every entry.
Provide a Resource Ref or External Ref so the resource can be matched unambiguously.
Provide a Project Ref, Alternate Project Ref, or Project name so the work can be matched.
Make sure the Date falls within a period that is still open for reconciliation.
To update an existing correction rather than create a new one, include its Record Id.
When submitting a batch, review the per-row results so you can correct and resubmit only the rows that failed.
Base URL
/rest/api/timesheetreconciliation
Rate Limits
Endpoint | Limit |
|---|---|
GET Find | 100 requests per 10 seconds |
POST single | 20 requests per 5 seconds |
POST bulk | 10 requests per 2 seconds |
Rate limit status is returned in response headers:
Header | Description |
|---|---|
| Maximum allowed requests in the window |
| Remaining capacity |
| Seconds until the window resets |
Endpoints
1. Find Correction Records by Date Range{#find}
Retrieves timesheet reconciliation correction records for the specified date range. Both startDate and endDate are mandatory.
HTTP Example
Endpoint: GET /rest/api/timesheetreconciliation/find
cURL Example
curl -X GET "https://organisation.fluid.work/rest/api/timesheetreconciliation/find?startDate=2026-07-01&endDate=2026-07-31&version=3.0" \
-H "Authorization: Bearer {your_api_token}" \
-H "Accept: application/json"
Query Parameters:
Parameter | Type | Required | Description |
|---|---|---|---|
| DateTime | Yes | Start of the date range (inclusive). ISO 8601 or |
| DateTime | Yes | End of the date range (inclusive). ISO 8601 or |
| string | No | API version (e.g. |
| string | No | Comma-separated list of fields to include in the response. |
| string | No | Comma-separated list of custom property expansions. |
| integer | No | Number of records to skip for pagination. Defaults to |
| integer | No | Number of records to return. Defaults to |
Response Headers:
Header | Description |
|---|---|
| Number of records returned in this response |
| Total number of matching records |
Response:
[
{
"fields": {
"recordId": 1042,
"date": "2026-07-01T00:00:00",
"resource": "Henry Rogers",
"resourceRef": "Henry.rogers",
"externalRef": "EMP-001",
"project": "Project Solara",
"projectRef": "ED-EN-1000",
"alternateProjectRef": null,
"financialRef": "FR-JC-01",
"task": null,
"subActivity": null,
"hours": 8.0,
"localValue": 0.0,
"localCurrencyCode": null,
"notes": null
}
}
]
Response (400 Bad Request) — missing or invalid date parameters:
{
"message": "startDate and endDate are required and must be valid dates."
}
Response (403 Forbidden):
{
"message": "You do not have the required permission to fetch timesheet reconciliation corrections."
}
2. Create Single Correction Entry
Creates or updates a single timesheet reconciliation correction entry.
HTTP Example
Endpoint: POST /rest/api/timesheetreconciliation
Request Body:
{
"fields": {
"recordId": 0,
"date": "2026-07-01T00:00:00Z",
"resourceRef": "Henry.rogers",
"projectRef": "ED-EN-1000",
"financialRef": "FR-JC-01",
"subActivity": "Application Support",
"hours": 8.0,
"localValue": 350.00,
"localCurrencyCode": "GBP",
"notes": "July correction"
}
}
cURL Example
curl -X POST "https://organisation.fluid.work/rest/api/timesheetreconciliation?version=3.0" \
-H "Authorization: Bearer {your_api_token}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"recordId": 0,
"date": "2026-07-01T00:00:00Z",
"resourceRef": "Henry.rogers",
"projectRef": "ED-EN-1000",
"financialRef": "FR-JC-01",
"subActivity": "Application Support",
"hours": 8.0,
"localValue": 350.00,
"localCurrencyCode": "GBP",
"notes": "July correction"
}
}'
Response — Valid entry:
{
"fields": {
"rowIndex": 1,
"isValid": true,
"status": "valid",
"validationMessages": []
}
}
Response — Validation error:
{
"fields": {
"rowIndex": 1,
"isValid": false,
"status": "invalid",
"validationMessages": [
"This row was skipped as Project 'Vacations' is not a valid Miscellaneous Task as configured in Timesheet Configuration."
]
}
}
Response (403 Forbidden):
{
"message": "You do not have the required permission to create timesheet reconciliation corrections."
}
3. Create Bulk Correction Entries
Submits multiple timesheet reconciliation correction entries in a single request. Each entry is independently validated and processed. Invalid rows do not prevent valid rows from being saved.
HTTP Example
Endpoint: POST /rest/api/timesheetreconciliation/bulk
Request Body:
[
{
"fields": {
"recordId": 0,
"date": "2026-07-01T00:00:00Z",
"resourceRef": "Henry.rogers",
"projectRef": "ED-EN-1000",
"hours": 8.0
}
},
{
"fields": {
"recordId": 1042,
"date": "2026-07-02T00:00:00Z",
"resourceRef": "Henry.rogers",
"projectRef": "ED-EN-1000",
"financialRef": "FR-JC-01",
"hours": 10.5
}
},
{
"fields": {
"recordId": 0,
"date": "2026-07-03T00:00:00Z",
"resourceRef": "unknown.user",
"projectRef": "ED-EN-1000",
"hours": 8.0
}
}
]
cURL Example
curl -X POST "https://organisation.fluid.work/rest/api/timesheetreconciliation/bulk?version=3.0" \
-H "Authorization: Bearer {your_api_token}" \
-H "Content-Type: application/json" \
-d '[
{
"fields": {
"recordId": 0,
"date": "2026-07-01T00:00:00Z",
"resourceRef": "Henry.rogers",
"projectRef": "ED-EN-1000",
"hours": 8.0
}
},
{
"fields": {
"recordId": 1042,
"date": "2026-07-02T00:00:00Z",
"resourceRef": "Henry.rogers",
"projectRef": "ED-EN-1000",
"financialRef": "FR-JC-01",
"hours": 10.5
}
}
]'
Response — Partial success:
{
"status": "partial",
"totalCount": 3,
"validCount": 2,
"invalidCount": 1,
"correlationId": "12345678-1234-1234-1234-123456789012",
"results": [
{
"fields": {
"rowIndex": 1,
"isValid": true
"status": "valid",
"validationMessages": [],
}
},
{
"fields": {
"rowIndex": 2,
"isValid": true
"status": "valid",
"validationMessages": [],
}
},
{
"fields": {
"rowIndex": 3,
"isValid": false
"status": "valid",
"validationMessages": [
"Row 3: no resource found matching the Resource Ref 'unknown.user'"
]
}
}
]
}
Request Model
The top-level request object wraps a fields object.
{
"fields": { ... }
}
Field | Type | Required | Description |
|---|---|---|---|
| integer | No | Id of an existing correction entry to update. Use |
| DateTime | Yes | Date of the correction entry. Must be after the Capitalization Lock Date. |
| string | Yes* | Resource reference ID (e.g. |
| string | Yes* | Resource employee ID. Alternative to |
| string | No | Project display name. Used to resolve miscellaneous task entries when |
| string | Yes** | Project External Reference (e.g. |
| string | Yes** | Project Alternate Reference. |
| string | No | Financial reference for the time entry (e.g. a cost code or WBS element). |
| string | No | Flex board task title. Used when the correction targets a flex board task entry. Cannot be combined with |
| string | No | Sub-activity type (e.g. |
| decimal | Yes | Hours for the correction. Must be greater than zero for new records ( |
| decimal | No | Override monetary value in local currency. When supplied alongside |
| string | No | Currency code for |
| string | No | Free-text notes attached to the correction entry. |
* Either resourceRef or externalRef is required.
** Either projectRef or alternateProjectRef is required (or project for miscellaneous task entries).
Response Models
Returned by both the single create and bulk create endpoints.
Field | Type | Description |
|---|---|---|
| string | Overall batch status: |
| integer | Total number of records submitted. |
| integer | Number of records that passed validation and were saved. |
| integer | Number of records that failed validation. |
| string | Unique GUID assigned to this request for tracking and log correlation. |
| array | List of |
status values
Value | Meaning |
|---|---|
| All submitted records were valid and saved. |
| Some records were valid and saved; others failed validation. |
| No records were valid; nothing was saved. |
| An unexpected processing error occurred. |
Per-row result
Field | Type | Description |
|---|---|---|
| integer | 1-based position of this row within the submitted list. |
| boolean |
|
| string |
|
| string[] | Array of validation error messages. Empty when valid. |
Response for 'Find' endpoint
Returned per record by the GET /find endpoint.
Field | Type | Description |
|---|---|---|
| integer |
|
| DateTime | Timesheet start date for this correction entry. |
| string | Resource full name. |
| string | Resource reference ID. |
| string | Resource employee ID. |
| string | Project or task display name. |
| string | Project external reference. |
| string | Project secondary external reference. |
| string | Financial reference for the time entry. |
| string | Flex board task title, if applicable. |
| string | Sub-activity type. |
| decimal | Recorded hours. |
| decimal | Stored local monetary value. |
| string | Local currency code. |
| string | Notes attached to the entry. |
Validation Rules
Validation runs in two phases: request-level (pre-processor) and processor-level.
Phase 1 — Request-Level Validation
Applied before the processor runs. A row that fails any of these checks is marked invalid and excluded from processor execution.
Rule | Error message |
|---|---|
|
|
|
|
Neither |
|
None of |
|
Phase 2 — Processor-Level Validation
Applied for each entry that passes Phase 1.
Rule | Error message fragment |
|---|---|
|
|
|
|
Resource not found by |
|
Resource not found by |
|
Resource has no resource plan for |
|
Project not found by |
|
Project type is excluded from timesheet reconciliation |
|
Project status prevents new entries |
|
|
|
|
|
Miscellaneous task name not found in configuration |
|
| task not found message |
|
|
|
|
|
|
|
|
Duplicate row within the batch (same resource + project + date + finRef + subActivity) | Only the most latest record in the duplicated list is considered for submission, rest all duplicate records are skipped with a duplicate-detected message |
Combination Matching for Updates (recordId > 0)
When recordId is greater than zero, the processor looks up the existing correction record by that ID and compares the following fields against what was submitted:
field |
|---|
|
Resource |
Project |
|
Task GUID |
|
If any field does not match, the row is rejected and the existing record is unchanged. Only hours, localValue, localCurrencyCode, and notes may differ from the stored values — all other fields act as an identity key to confirm the correct record is being updated.
Processing Behaviour
Request validation: Each row is checked against the mandatory field rules..
Duplicate removal: Rows sharing the same
(resourceRef, projectRef, date, financialRef, subActivity)key within a single batch are deduplicated. The row that is latest in the duplicated combination list is kept; earlier duplicates are rejected without processing.Processor execution: All valid entries are submitted.
Versioning
The API supports versioning via the version query parameter:
version=3orversion=3.0— V3 API (current)Omitted — resolves to the latest stable version (currently V3)
POST /rest/api/timesheetreconciliation?version=3.0
Field Filtering
Use the fields query parameter to limit which fields appear in the response:
GET rest/api/timesheetreconciliation/find?startDate=2026-08-01&endDate=2026-08-30&fields=resourceRef,projectRef,recordid
Best Practices
Use the Find endpoint before bulk updates: Call
GET /rest/api/timesheetreconciliation/findfirst to retrieve currentrecordIdvalues and the exact field values stored in the database. This ensures the combination check passes when you submit updates.Treat
recordIdas an opaque identifier: Source it from the 'Find' endpoint.For updates, only change
hours,localValue,localCurrencyCode, ornotes: Any change todate,resourceRef,projectRef,financialRef,subActivity, ortaskon a row withrecordId > 0will fail the combination check and the row will be rejected.Use the bulk endpoint for multi-row submissions: The bulk endpoint processes all rows in a single batch and returns per-row results. Sending rows individually across multiple single POST calls is less efficient.
Check
isValidper row: Iterateresultsand checkisValidto identify rejected rows and theirvalidationMessages.Handle partial success: The
statusfield signals"success","partial", or"failed".Respect the Capitalization Lock Date: Entries with a
dateon or before the Capitalization Lock Date are always rejected. Verify the lock date before submitting historical corrections.Miscellaneous task entries: For entries targeting a miscellaneous task rather than a standard project, set the
projectfield to the task display name and leaveprojectRefandalternateProjectRefempty. Do not includesubActivityon miscellaneous task rows.Flex board task entries: Set the
taskfield to the exact flex board task title. Do not combinetaskwithfinancialRef..Use field filtering: Use the
fieldsquery parameter to reduce response payload size when only specific fields are needed.