Skip to content
ShiftlyDevelopers
Documentation menu

Labour costs

Rostered and actual hours and cost per calendar day and location, against the location's labour target. Rostered figures need rostering access and actual figures need timesheet access; costs need pay access. Days with no shifts or timesheets are left out. Sales are not included, so the labour percentage itself is yours to work out.

Needs one of the roster:read or timesheets:read permissions, depending on the operation. The business sees it as "Rosters and shifts".

Fields

LabourCostDay fields
FieldTypeAccessMeaning
datedateRead-onlyThe calendar day in the location's timezone.
location_idstringRead-onlyThe location.
position_idstring, may be nullRead-onlyThe position, when grouped by position.
target_labour_percentagenumber, may be nullRead-onlyThe location's labour cost target, as a percentage of sales. Returned only with settings:read.
rosteredobjectRead-onlyShifts starting that day, published and draft. Returned only with roster:read.
actualobjectRead-onlyTimesheets starting that day, approved and pending. Rejected and still-open timesheets are left out. Returned only with timesheets:read.

Operations

List rostered and actual labour by day and location

GET/v1/labour-costs

Permission: roster:read, timesheets:read Needs any one of: roster:read, timesheets:read.

Query parameters
ParameterTypeMeaning
fromdateRequiredThe first day of the range, in the location's timezone. With to, at most 31 days.
todateRequiredThe last day of the range, inclusive.
location_idstringOptionalOnly this location.
group_by"position"Optional
200 response
{
  "data": [
    {
      "date": "2026-10-06",
      "location_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "position_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "target_labour_percentage": 1.5,
      "rostered": {
        "published_shift_count": null,
        "published_hours": null,
        "published_cost": null,
        "draft_shift_count": null,
        "draft_hours": null,
        "draft_cost": null,
        "open_shift_count": null
      },
      "actual": {
        "approved_hours": null,
        "approved_count": null,
        "approved_cost": null,
        "pending_hours": null,
        "pending_count": null,
        "pending_cost": null
      }
    }
  ],
  "has_more": true,
  "next_cursor": "text"
}
Refusals
StatusWhen
400The error's code is invalid_request or range_too_long. The Errors page describes each code.
401The error's code is invalid_token or token_expired. The Errors page describes each code.
403The error's code is origin_not_allowed, permission_denied, not_available, connection_disconnected, connection_suspended or app_suspended. The Errors page describes each code.
404There is nothing at this address, or no such record in this business.
429Too many requests. Retry-After says when to try again.
500Something went wrong at Shiftly. Quote the request id.
503This environment is not set up for partner apps yet.