Time Entries (Field Time)
The Field Time REST API exposes a clean, versioned surface for reading and writing time entries.
It supports fetching a single entry, searching with filter criteria, upserting (combined add or
update) one or more entries, and reading supporting lookup values. All endpoints live under
/api/ft/public/v1/ and are protected by OAuth bearer tokens. (ex. https://{JonasCustomerSubDomain}.jonasapp.com:8091/api/ft/public/v1/time-entries)
/api/ft/public/v1/
Authentication
Every /api/ft/public/ endpoint requires a valid bearer token. The controller validates
the token's jpt (principal-type) claim and the caller's API license on every request.
See Authentication to obtain a token, then send it as:
Authorization: Bearer <access_token>Get a time entry
/api/ft/public/v1/time-entries/{entryId}
Retrieve a single time entry by its ID. Returns 200 OK with the time entry as a plain
JSON object (not wrapped in an outer property), or 404 Not Found when the entry does not
exist or is not visible to the caller.
GET /api/ft/public/v1/time-entries/4821{
"entryId": 4821,
"userId": "JSMITH",
"employee": "Jane Smith",
"entryDate": "2026-06-05",
"payroll": "REG",
"payrollCompany": "01",
"allocationType": "J",
"field1": "J-1001",
"field2": "100",
"field3": "",
"earningCode": "REG",
"earningValue": 8.0,
"occupation": "CARP",
"union": "",
"entryTypeId": 1,
"status": 1,
"inputMode": 1,
"startTime": "07:00",
"endTime": "15:00",
"notes": "",
"crewId": null,
"reasonId": 0,
"changeComments": null,
"timeEntryCustomFields": [],
"entryChangeHistories": []
}The response omits SPA-internal fields (grid IDs, approver IDs, attachments, timer/clock metadata, computed hours/qty/dollars, and display-only names) that have no meaning to external integrators.
Search time entries
/api/ft/public/v1/time-entries/search
Search accepts its filter criteria as a JSON body — for example a user and a date range. Pagination
is supplied with the page and pageSize query parameters.
POST /api/ft/public/v1/time-entries/search?page=1&pageSize=50{
"userId": "JSMITH",
"startDate": "2026-06-01",
"endDate": "2026-06-07",
"companyCode": "01",
"payrollCode": "REG",
"status": [1, 2]
}| Field | Description |
|---|---|
userId | Required. Filter entries belonging to a specific user. |
startDate | Optional. Start of the date range (inclusive). Omit for no lower bound. |
endDate | Optional. End of the date range (inclusive). Omit for no upper bound. |
companyCode | Optional. Restrict results to a specific payroll company. |
payrollCode | Optional. Restrict results to a specific payroll/earning code. |
status | Optional. Array of entry-status codes to include. See entry statuses. |
| Query parameter | Description |
|---|---|
page | 1-based page number. Defaults to 1. |
pageSize | Results per page. Defaults to 50, maximum 500. |
The response is a pagination envelope. entries uses the same field set as
Get a time entry.
{
"page": 1,
"pageSize": 50,
"totalCount": 2,
"entries": [
{ "entryId": 4821, "userId": "JSMITH", "entryDate": "2026-06-05", "...": "..." },
{ "entryId": 4830, "userId": "JSMITH", "entryDate": "2026-06-06", "...": "..." }
]
}Upsert time entries
/api/ft/public/v1/time-entries
The upsert endpoint accepts a batch of one or more entries in a single request — it
handles both creating and updating. Entries without an entryId (or with
entryId: 0) are created; entries with an existing entryId are updated.
The request below is an example only. Any entry may also include the
optional fields (such as occupation,
startTime/endTime, notes, crewId, and
entryId for updates) in addition to the fields shown.
{
"userId": "JSMITH",
"entries": [
{
"userId": "JSMITH",
"employee": "00001",
"payrollCompany": "LC",
"clientCompany": "LC",
"country": "CA",
"union": "UN01",
"payroll": "WK.5",
"earningCode": "H01",
"earningValue": 8.25,
"entryDate": "2026-08-24",
"allocationType": "J/C",
"field1": "*LYD1",
"field2": "00000",
"field3": "1A",
"ppEnd": "2026/08/28",
"inputMode": 1
}
]
}The request body has two batch-level fields:
| Field | Description |
|---|---|
userId | Required. The user the batch is submitted for. |
entries | Required, non-empty array of entry objects. Each entry accepts the required and optional fields listed below. |
Required entry fields. For a web-import create request, each entry requires the fields below. Codes must match values configured for the target Jonas customer.
| Entry field | Requirement and format |
|---|---|
userId | Required. User ID as a string; normally matches the batch-level userId. |
employee | Required. Employee code as a string. |
payrollCompany | Required. Payroll company code as a string. |
clientCompany | Required. Client company code as a string. |
country | Required. Two-character country code, such as CA. |
payroll | Required. Payroll code as a string. |
earningCode | Required. Earning code as a string. |
earningValue | Required. Hours or quantity as a JSON number. |
entryDate | Required. Entry date in YYYY-MM-DD format. |
allocationType | Required. Allocation type code as a string, such as J/C. |
field1, field2, field3 | Required. Allocation segment values as strings. |
ppEnd | Required. Pay-period end date in YYYY/MM/DD format. |
inputMode | Required. Integer input-mode code. See input modes. |
Optional entry fields. These fields may be included on any entry, for both creates and updates unless noted otherwise.
| Entry field | Description |
|---|---|
entryId | Send an existing entry ID to update that entry; omit it (or send 0) to create a new entry. |
id | A client-generated local/offline identifier (e.g. a UUID) for correlating batched or offline-queued entries with their result. Echoed back as localId in the corresponding upsert response entry. If omitted on a create, the server assigns a UUID. |
country | Optional on updates only; on web-import creates it is required (see required fields above). Two-character country code, such as CA. |
union | Union code as a string. Send an empty string when the employee is non-union. |
jobUnion | Job-level union code override, when the job's union differs from the employee's. |
occupation | Occupation (trade) code as a string. |
jobOccupation | Job-level occupation code override, when the job's occupation differs from the employee's. |
entryTypeId | Integer entry-type code. See entry types. |
startTime, endTime | Start and end times in HH:mm 24-hour format, for example 07:00. |
breakDetails, breakTime | Break detail and break time values, for entries that record unpaid breaks. |
notes | Free-text note attached to the entry. |
field1descr, field2descr, field3descr | Descriptions for the allocation segment values in field1–field3. |
equipment | Equipment code, for entries allocated to equipment. |
eqpCostItem | Equipment cost-item code, used together with equipment. |
ppStart, ppEnd | Pay-period start and end dates in YYYY/MM/DD format. On updates, both must be sent and must together match a web-enabled pay period for the entry's payroll. (ppEnd is also required on creates; see required fields above.) |
certifiedPayroll | Certified payroll code, for jobs subject to certified payroll reporting. |
crewId | Integer crew ID. See crews. |
reasonId | Integer change-reason code, used when updating an existing entry. See change reasons. |
changeComments | Free-text comment recorded in the entry's change history when updating. |
Fields not listed above — status, display-only names and descriptions
(employeeName, earningCodeDesc, entryTypeName,
statusName, crewName, crewDescription), computed values
(hours, qty, dollars, breakTotal,
breakHour, timeEntriesRoundedTime), SPA-internal identifiers
(gridId, parentId, approverId, clockTimerEntryId,
timerColor, changeDetails), and entryChangeHistories — are
server-computed or SPA-internal and are ignored when sent on upsert.
The response returns one result per submitted entry, in the same order, rather than the saved entry objects themselves:
{
"entries": [
{
"entryId": 4821,
"localId": "f163b4d2-5ccb-4e4b-9c3b-34cddd96aa3b",
"success": true,
"message": null,
"entryChangeHistories": []
}
]
}| Field | Description |
|---|---|
entryId | The created or updated entry's ID. |
localId | Echoes the client-supplied id, if one was sent; otherwise contains the server-generated UUID assigned to a create that omitted id. |
success | Derived: true when entryId > 0 and message is empty. |
message | Failure detail for this entry, if any. |
entryChangeHistories | Change history entries recorded as a result of this save. |
Attachments and custom fields are not returned by upsert (v1 scope). Use Get a time entry to read back full entry details after an upsert. There is no plain unfiltered listing — use search to retrieve sets of entries.
Lookups
Supporting reference data used to populate pickers and validate the fields above. All lookup endpoints require the same bearer token as the time entry endpoints.
Entry statuses
/api/ft/public/v1/lookups/entry-statuses
Returns all time entry lifecycle status codes, for use with the search status filter.
Entry types
/api/ft/public/v1/lookups/entry-types
Returns configured entry types, for use with the entryTypeId field.
Input modes
/api/ft/public/v1/lookups/input-modes
Returns valid time entry input modes, for use with the inputMode field.
The three lookups above share the same code/name shape:
[
{ "code": 1, "name": "Approved" },
{ "code": 2, "name": "Pending" }
]Change reasons
/api/ft/public/v1/lookups/change-reasons
Returns valid change reason codes, for use with the reasonId field.
Crews
/api/ft/public/v1/lookups/crews
Returns crew IDs and names visible to a user within a company, for use with the crewId
field.
GET /api/ft/public/v1/lookups/crews?company=01&user=JSMITH&search=framing| Query parameter | Description |
|---|---|
company | Required. Payroll company code to scope crews to. |
user | Required. User whose visible crews are returned. |
search | Optional. Filters crews by name or description (contains, case-insensitive). |
[
{ "crewId": 12, "name": "Framing Crew A", "companyCode": "01" }
]Custom fields
/api/ft/public/v1/lookups/custom-fields
Returns custom field definitions configured for a company.
GET /api/ft/public/v1/lookups/custom-fields?company=01| Query parameter | Description |
|---|---|
company | Required. Payroll company code to scope custom fields to. |
[
{
"fieldId": 3,
"name": "PO Number",
"fieldType": 1,
"active": true,
"allowedValues": [
{ "id": 1, "shortForm": "PO1", "description": "Purchase Order 1", "isDefault": false }
]
}
]Errors
Errors are returned as RFC 7807 problem detail documents. See REST API Overview → Error responses for the common status codes and shape.