Use the Labor API to record shifts worked by team members, including the shift's start and end times, job title, pay rate, and breaks. Shift records can be used for payroll, labor cost reporting, and overtime management and to inform scheduling decisions.
Applies to: Labor API | Team API | Locations API
Learn how to start a shift with an assigned job title and pay rate for a team member using the following steps:
- Get the ID of the shift location.
- Get the ID of the team member.
- Verify that the team member doesn't already have an open shift.
- Get wage information for the job to be done on the shift.
- Create a new shift with the start time and information you collected. This step sets the shift status to
OPEN
.
This topic also shows how to end the shift using the following steps:
- Get the open shift.
- Update the shift with the end time. This step sets the shift status to
CLOSED
.
You need a valid access token - The steps in this topic call Square APIs in the Square Sandbox, so you can use your Sandbox access token in the requests. Square recommends testing with Sandbox credentials when possible.
Applications that use OAuth access tokens in the production environment require the MERCHANT_PROFILE_READ
, EMPLOYEES_READ
, TIMECARDS_READ
, and TIMECARDS_WRITE
permissions to perform these steps. When calling Square APIs in the production environment, change the base URL to https://connect.squareup.com
.
You need a team member with an assigned wage setting - To create a shift, you must provide the ID of a team member who's active at the shift location. If needed, you can create and set up a team member using the Square Dashboard or Team API.
Step 1: Get the shift location
If needed, you can call ListLocations and then copy the ID of the shift location.
Step 2: Get the team member
Call SearchTeamMembers to get active team members for a location using the location_ids
and status
query filters. Then, copy the ID of the team member who's working the shift.
The response returns an array of TeamMember
objects representing the active team members for the specified location.
{
"team_members": [
{
"id":
"-3oZQKPKVk6gUXU_V5Qa",
"reference_id":
"12345678",
"is_owner":
false,
"status":
"ACTIVE",
"given_name":
"Sara",
"family_name":
"Vera",
"email_address":
"[email protected]",
"created_at":
"2019-01-10T17:26:48Z",
"updated_at":
"2020-04-28T21:49:28.957Z",
"assigned_locations": {
"assignment_type":
"ALL_CURRENT_AND_FUTURE_LOCATIONS"
}
},
{
"id":
"1AVJj0DjkzbmbJw5r4KK",
"reference_id":
"abcded",
"is_owner":
false,
"status":
"ACTIVE",
"given_name":
"Ricardo",
"family_name":
"Mariano",
"phone_number":
"+14155552671",
"created_at":
"2020-03-24T18:14:01.127Z",
"updated_at":
"2020-06-09T17:38:05.423Z",
"assigned_locations": {
"assignment_type":
"ALL_CURRENT_AND_FUTURE_LOCATIONS"
}
},
{
"id":
"2JCmiJol_KKFs9z2Evim",
"is_owner":
false,
"status":
"ACTIVE",
"given_name":
"Michelle",
"family_name":
"Chan",
"created_at":
"2020-03-24T01:09:25.010Z",
"updated_at":
"2020-03-24T01:09:25.010Z",
"assigned_locations": {
"assignment_type":
"ALL_CURRENT_AND_FUTURE_LOCATIONS"
}
}
],
"cursor":
"N:9UglUjOXQ13-hMFypCft"
}
The limit
in the example request defines the page size of responses. The cursor
in the example response is used to get the next page of results. For more information, see Pagination.
Step 3: Get the team member wage types
Call ListTeamMemberWages using the team_member_id
query filter to get available wage types for the team member. A team member might have multiple wage types, so you need to find the title and pay rate for the job that the team member is performing for the shift.
The response returns an array of TeamMemberWage
objects associated with the team member.
{
"team_member_wages": [
{
"id": "iVLHz3adFg6kXJESFpwBvqiH",
"team_member_id": "-3oZQKPKVk6gUXU_V5Qa",
"title": "Manager",
"hourly_rate": {
"amount": 2500,
"currency": "USD"
},
"job_id": "god1UVkdSodJ1F4PCzoA8y6d",
"tip_eligible": true
}
]
}
The first team member wage type in the array represents the team member's primary job.
Step 4: Check for an open shift record
Call SearchShifts to search for an open shift for the team member using the status
, team_member_ids
, and location_ids
query filters. A new shift cannot be created for a team member until the previous shift is ended.
This filter always returns zero or one Shift
object because a team member can have a maximum of one shift with an OPEN
status.
If the team member doesn't have an open shift, the response returns an empty object.
Step 5: Build a shift object
Call CreateShift to create a new shift using the location ID and team member ID you copied in previous steps. For the wage
field, you can provide the title, pay rate, and tip eligibility from the wage type that corresponds to the job to be done on the shift. The start_at
field can be set to local time or GMT. If you use GMT, Square calculates the local time based on the shift location. If the shift creation request succeeds and your application subscribed to Labor API webhooks, a labor.shift.created webhook event is fired.
Important
To record labor cost, you must include the wage
field with an hourly_rate
. Otherwise, the shift record has no associated pay amount. The job title and pay rate from the team member's primary job aren't used by default.
Step 1: Get the shift to close
Call SearchShifts to get the open shift for the team member using the status
, team_member_ids
, and location_ids
query filters.
The response should return the Shift
object you created in the previous section.
{
"shifts": [
{
"id": "3DBHNF9E8CG27",
"employee_id": "-3oZQKPKVk6gUXU_V5Qa",
"location_id": "KACM8A41GR60X",
"timezone": "America/Los_Angeles",
"start_at": "2019-02-05T12:00:00-08:00",
"wage": {
"title": "Manager",
"hourly_rate": {
"amount": 2500,
"currency": "USD"
},
"job_id": "J8p7B7nyVA3QfMdnU1BkEfjP",
"tip_eligible": true
},
"declared_cash_tip_money": {
"amount": 0,
"currency": "USD"
},
"status": "OPEN",
"version": 1,
"created_at": "2019-02-05T11:58:49-08:00",
"updated_at": "2019-02-05T11:58:49-08:00",
"team_member_id": "-3oZQKPKVk6gUXU_V5Qa"
}
]
}
Verify that any breaks are ended
Inspect the shift for a breaks
field, which is added to a shift if the team member took any breaks. If you're following the steps in this topic, you shouldn't see this field because no breaks were taken.
For shifts that do include the breaks
field, confirm that each break contains an end_at
field with a valid timestamp. If the shift has an open break, you need to end the break before you can end the shift.
To close a shift, call UpdateShift and add an end_at
field to the open shift.
The response returns the updated version of the shift with a CLOSED
status and an incremented version number.
{
"shift": {
"id": "3DBHNF9E8CG27",
"employee_id": "-3oZQKPKVk6gUXU_V5Qa",
"location_id": "KACM8A41GR60X",
"timezone": "America/Los_Angeles",
"start_at": "2019-02-05T12:00:00-08:00",
"end_at": "2019-02-05T19:56:09-08:00",
"wage": {
"title": "Manager",
"hourly_rate": {
"amount": 2500,
"currency": "USD"
},
"job_id": "J8p7B7nyVA3QfMdnU1BkEfjP",
"tip_eligible": true
},
"declared_cash_tip_money": {
"amount": 0,
"currency": "USD"
},
"status": "CLOSED",
"version": 2,
"created_at": "2019-02-05T11:58:49-08:00",
"updated_at": "2019-02-05T19:56:09-08:00",
"team_member_id": "-3oZQKPKVk6gUXU_V5Qa"
}
}
Note that you can update the wage
or declared_cash_tip_money
field for the shift at any time.