Field Productivity
Introduction
This tutorial provides insight and guidance for developers using the Field Productivity resources and endpoints available in the Procore API. Procore’s Project-level Timesheets tool is designed for self-perform contractors who manage internal labor resources on site. Contractors use time tracking information for payroll and labor productivity reporting.
Prior to working with the Field Productivity resources and endpoints, we recommend reviewing our Timecard and Timesheet articles on the Procore Support Site. We also encourage you to view our informative How-to Training Videos to gain a deeper understanding of our Field Productivity tools.
Timecard Entries
A Timecard Entry is the most basic element for tracking employee time information. These records contain all key data, such as employee name, hours worked, work performed, etc. In Procore, Timecard Entries are created from several places - Timesheets, the Daily Log, and the company-level Timecard tool. Procore users are restricted to which fields they can fill out depending on where the entry is created from. In Procore reporting tools (Custom Reports, Labor Budget to Actual, Field Production Report, etc.), all Timecard entries are listed regardless of which tool they were created in.
Timecard Entry Endpoints
The Procore API provides the following endpoints for working with Timecard Entries.
Endpoint | Description |
---|---|
List Timecard Entries | Returns a list of pending Timecard Entries in the specified Project. |
Create Timecard Entry | Creates a new Timecard Entry for the specified Project for a given timesheet ID. |
Show Timecard Entry | Returns details for a given Timecard Entry in the specified Project. |
Update Timecard Entry | Updates the information for a given Timecard Entry in the specified Project. |
Delete Timecard Entry | Deletes a given Timecard Entry in the specified Project. |
Timesheets
Each Timesheet represent a grouping of one or more Timecard Entries for one day. When Timecard Entries are associated with a Timesheet, users are able to interact with them in the Timesheets tool. Timesheets offer the most advanced time tracking functionality in the Procore web app, allowing users to attach a signature, approve entries, fill out production quantities, and more.
TIME ENTRY SETTINGS
Timesheets are configured for time entry at the project level using either Total Hours or Start Time and Stop Time. It is important to note that when you create timecard entries for a timesheet using the API, you must use paramters consistent with the time entry setting for the particular timesheet you are working with. For example, if the timesheet is configured for Total Hours time entry then you would simply use the
hours
parameter. Alternately, if the timesheet is configured to use Start Time and Stop Time, you would use thetime_in
,time_out
, andlunch_time
parameters. Under this scenario,time_in
andtime_out
are passed as ISO8601-compliant strings andlunch_time
is passed as the number of minutes spent for a lunch break.
Timesheet Endpoints
The Procore API provides the following endpoints for working with Timesheets.
Endpoint | Description |
---|---|
List All Timesheets | Returns a list of all Timesheets in a specified Project. |
Show a Timesheet | Returns detailed information for a given Timesheet in a specified Project. |
Create Timesheet | Creates a new Timesheet in the specified Project. |
Get a List of Possible Timesheet Creators | Returns a list of all potential Timesheet Creators for a specified Project. |
Get A List of Possible Timesheet Creator Ids | Returns a list of all potential Timesheet Creator Ids for a specified Project. |
List Cost Codes for Timesheets | Returns a list of Cost Codes for Timesheets in a specified Project. |
List Cost Code Ids for Timesheets | Returns a list of Cost Code Ids for Timesheets in a specified Project. |
Update Timesheet Status | Updates the status of a given Timesheet as either pending/approved in a specified Project. |
List Change History for Timesheet | Returns Change History for a given Timesheet in a specified Project. |
Create Signature for Timesheet | Create new Signature associated with a specified Project. |
Show a Signature | Return detailed information on a given Signature in a specified Project. |
Typical Example Workflow
To help illustrate the relationship between Timecard Entries and Timesheets, let’s work through a typical example of a Field Productivity workflow. In this example we will create a new Timesheet, add a Timecard Entry to the new Timesheet, update the time worked on the Timecard Entry, then finally approve the Timesheet.
1. Create a New Timesheet
Use the Create Timesheet endpoint (POST /rest/v1.0/projects/{project_id}/timesheets) to create a new Timesheet grouping object. Here is a cURL example showing this call:
curl -H "Content-type: application/json" -H "Authorization: Bearer <access token>" \
-X POST -d '{"timesheet":{"date":"2018-11-01"}}' https://api.procore.com/rest/v1.0/projects/123456789/timesheets
Note that we specify the Content-type
as application/json
and include the oAuth 2.0 access token in the request header using -H
flags.
In addition, we include the JSON payload for the new timesheet using the -d
flag.
Running this call returns a JSON response similar to the following:
{
"id": 12345,
"created_at": "2018-11-01T18:20:24Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"date": "2018-11-01",
"name": "2018-11-01 - 01",
"number": 1,
"status": "pending",
"timecard_entries": [],
"updated_at": "2018-11-01T18:20:24Z"
}
2. Create a Timecard Entry in a Timesheet
Use the Create Timecard Entry endpoint (POST /rest/v1.0/projects/{project_id}/timecard_entries) to create an entry (or entries) for each employee.
Include the timesheet_id
for each Timecard Entry.
The value should match the id of the Timesheet you created in Step 1.
Here is the cURL example for this call.
Note that we are using the time_in
, time_out
, and lunch_time
parameters as the means for defining duration of work performed.
curl -H "Content-type: application/json" -H "Authorization: Bearer <access token>" \
-X POST -d '{"timecard_entry": {"lunch_time": "60", \
"time_in": "08:00", \
"time_out": "17:00", \
"billable": true, \
"date": "2018-11-01", \
"description": "Final cleanup", \
"timecard_time_type_id": 9185, \
"timesheet_id": 12345, \
"cost_code_id": 153428166}}' \
https://api.procore.com/rest/v1.0/projects/123456/timecard_entries
Running this call returns a JSON response similar to the following:
{
"id": 1234567,
"approval_status": "pending",
"billable": true,
"cost_code": {
"id": 153428166,
"biller_id": 123456,
"biller_type": "Project",
"code": "740",
"created_at": "2017-10-30T18:31:57Z",
"deleted_at": null,
"full_code": "06-200",
"long_name": "06-200 - Finish Carpentry",
"name": "Finish Carpentry",
"parent_id": 153428034,
"position": null,
"sortable_code": "06-200",
"standard_cost_code_id": 3523579,
"updated_at": "2017-10-30T18:31:57Z"
},
"created_at": "2018-11-01T19:10:25Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"crew": null,
"date": "2018-11-01",
"deleted_at": null,
"description": "Completed workbench countertops in garage.",
"hours": "8.0",
"injured": null,
"location": null,
"login_information": null,
"lunch_time": 60,
"party": null,
"permissions": {
"can_update": true,
"can_delete": true
},
"signature": null,
"sub_job": null,
"time_in": "2018-11-01T08:00:00Z",
"time_out": "2018-11-01T17:00:00Z",
"timecard_time_type": {
"id": 9185,
"abbreviated_time_type": "REG",
"company_id": 1234,
"global": null,
"time_type": "Regular Time"
},
"timesheet": {
"id": 12345,
"created_at": "2018-11-01T18:20:24Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"date": "2018-11-01",
"name": "2018-11-01 - 01",
"number": 1,
"status": "pending",
"updated_at": "2018-11-01T18:20:24Z"
},
"timesheet_status": "pending",
"updated_at": "2018-11-01T19:10:25Z"
}
The Timecard Entry you created will now show up in the associated timesheet viewable in the Timesheets tool in Procore, or via the Timesheets Index endpoint.
3. Update a Timecard Entry
Use the Update Timecard Entry endpoint (UPDATE /rest/v1.0/projects/{project_id}/timecard_entries/{id}) to update an existing Timecard Entry. One possile scenario is updating the duration of work for an existing Timecard Entry. Here is a cURL example illustrating this action:
curl -H "Content-type: application/json" -H "Authorization: Bearer <access token>" \
-X PATCH -d '{"timecard_entry": {"lunch_time": "30", \
"time_in": "08:00", \
"time_out": "17:00", \
"description": "Correcting lunch time to 30 minutes"}}' \
https://api.procore.com/rest/v1.0/projects/123456/timecard_entries/1234
Here we have adjusted the lunch time from 60 to 30 minutes and added a description for the change. Running this call returns a JSON response similar to the following:
{
"id": 12345678,
"approval_status": "pending",
"billable": true,
"cost_code": {
"id": 153428166,
"biller_id": 123456,
"biller_type": "Project",
"code": "200",
"created_at": "2017-10-30T18:31:57Z",
"deleted_at": null,
"full_code": "06-200",
"long_name": "06-200 - Finish Carpentry",
"name": "Finish Carpentry",
"parent_id": 153428034,
"position": null,
"sortable_code": "06-200",
"standard_cost_code_id": 3523579,
"updated_at": "2017-10-30T18:31:57Z"
},
"created_at": "2018-11-01T19:10:25Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"crew": null,
"date": "2018-11-01",
"deleted_at": null,
"description": "Correcting lunch time to 30 minutes.",
"hours": "8.5",
"injured": null,
"location": null,
"login_information": null,
"lunch_time": 30,
"party": null,
"permissions": {
"can_update": true,
"can_delete": true
},
"signature": null,
"sub_job": null,
"time_in": "2018-11-01T08:00:00Z",
"time_out": "2018-11-01T17:00:00Z",
"timecard_time_type": {
"id": 9185,
"abbreviated_time_type": "REG",
"company_id": 1234,
"global": null,
"time_type": "Regular Time"
},
"timesheet": {
"id": 12345,
"created_at": "2018-11-01T18:20:24Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"date": "2018-11-01",
"name": "2018-11-01 - 01",
"number": 1,
"status": "pending",
"updated_at": "2018-11-01T18:20:24Z"
},
"timesheet_status": "pending",
"updated_at": "2018-11-01T19:44:40Z"
}
4. Update the Status of a Timesheet (Approve)
In the final step of this exercise we update the status of our Timesheet from pending
to approved
using the Update Timesheet Status endpoint (PATCH /rest/v1.0/projects/{project_id}/timesheets/update_approval).
Here is a cURL example illustrating this action:
curl -H "Content-type: application/json" -H "Authorization: Bearer <access token>" \
-X PATCH -d '{"timesheets": [{ \
"id": 12345, \
"status": "approved"}]}' \
https://api.procore.com/rest/v1.0/projects/123456/update_approval
Running this call returns a JSON response similar to the following:
[
{
"id": 12345,
"name": "2018-11-01 - 01",
"date": "2018-11-01",
"status": "approved",
"created_at": "2018-11-01T18:20:24Z",
"updated_at": "2018-11-01T21:16:45Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"timecard_entries": [
{
"id": 12345678,
"created_at": "2018-11-01T19:10:25Z",
"date": "2018-11-01",
"deleted_at": null,
"description": "Correcting lunch time to 30 minutes.",
"hours": "8.5",
"updated_at": "2018-11-01T21:16:45Z",
"time_in": "2018-11-01T08:00:00Z",
"time_out": "2018-11-01T17:00:00Z",
"injured": null,
"lunch_time": 30,
"billable": true,
"party_id": null,
"origin_id": null,
"origin_data": null,
"crew": {
"id": null,
"name": null
},
"timesheet_status": "approved",
"timesheet": {
"id": 12345,
"name": "2018-11-01 - 01",
"date": "2018-11-01",
"status": "approved",
"created_at": "2018-11-01T18:20:24Z",
"updated_at": "2018-11-01T21:16:45Z",
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
}
},
"cost_code": {
"id": 153428166,
"name": "Finish Carpentry",
"long_name": "06-200 - Finish Carpentry",
"full_code": "06-200",
"sortable_code": "06-200"
},
"created_by": {
"id": 1234567,
"login": "jim.smith@example.com",
"name": "Jimmy Smith"
},
"timecard_time_type": {
"id": 9185,
"abbreviated_time_type": "REG",
"company_id": 1234,
"global": null,
"time_type": "Regular Time"
}
}
]
}
]
The Timesheet you updated will now show up as approved
when viewed in the Timesheets tool in Procore, or via the List All Timesheets endpoint (GET /rest/v1.0/projects/{project_id}/timesheets).