Skip to content
ShiftlyDevelopers
Documentation menu

Shifts

Rostered shifts. A shift your app creates is a draft until a manager publishes the roster in Shiftly. Any shift that has not started can be changed or deleted; a change to a published shift makes it a draft again until a manager republishes.

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

Fields

Shift fields
FieldTypeAccessMeaning
idstringRead-onlyThe shift.
location_idstringWritableWhere the shift is.
position_idstringWritableThe position being worked.
employee_idstring, may be nullWritableWho is rostered. Empty for an open shift.
roster_idstringRead-onlyThe roster week Shiftly placed the shift in.
start_timetimestampWritableWhen the shift starts.
end_timetimestampWritableWhen the shift ends.
status"unpublished", "published", "expired"Read-onlyunpublished (a draft), published or expired. Only a manager in Shiftly publishes.
breaksarray of objectWritablePlanned breaks. Left out on create, or when a change moves the start or end, Shiftly plans them from the award.
notesstring, may be nullWritableThe note on the shift, where the connecting person may see it.
project_idstring, may be nullRead-onlyThe project the shift is charged to, if any.
paid_hoursnumber, may be nullRead-onlyHours paid, after unpaid breaks.
costobjectRead-onlyEstimated labour cost in dollars. Zero for an open shift. Returned only with pay:read.
created_by_appbooleanRead-onlyTrue when your app created this shift.
archivedbooleanRead-onlyTrue when the record has been removed in Shiftly.
created_attimestampRead-onlyWhen the record was created.
updated_attimestampRead-onlyWhen the record last changed.

Operations

List shifts

GET/v1/shifts

Permission: roster:read

Query parameters
ParameterTypeMeaning
limitinteger, default 50, up to 200OptionalHow many records per page. Up to 200.
afterstringOptionalThe next_cursor from the previous page.
updated_sincetimestampOptionalOnly records changed at or after this moment. Pair it with include_archived to see removals.
include_archived"true", "false"OptionalInclude records that have been archived.
fromdateOptionalThe first day of the range, in the location's timezone. With to, at most 92 days.
todateOptionalThe last day of the range, inclusive.
location_idstringOptionalOnly this location.
employee_idstringOptionalOnly this person.
200 response
{
  "data": [
    {
      "id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "location_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "position_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "employee_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "roster_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "start_time": "2026-10-06T09:00:00+11:00",
      "end_time": "2026-10-06T09:00:00+11:00",
      "status": "unpublished",
      "breaks": [],
      "notes": "text",
      "project_id": "66f1c2a4b3d9e8f7a6b5c4d3",
      "paid_hours": 1.5,
      "cost": {
        "total": null,
        "subtotal": null,
        "super": null,
        "allowances": null,
        "position_loading": null,
        "breakdown": null
      },
      "created_by_app": true,
      "archived": true,
      "created_at": "2026-10-06T09:00:00+11:00",
      "updated_at": "2026-10-06T09:00:00+11:00"
    }
  ],
  "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.

Create one draft shift, or up to 100 in one all-or-nothing request

POST/v1/shifts

Permission: roster:write

Request body
FieldTypeRequiredMeaning
location_idstringRequiredWhere the shift is.
position_idstringRequiredThe position being worked.
employee_idstring, may be nullOptionalWho is rostered. Empty for an open shift.
start_timetimestampRequiredWhen the shift starts.
end_timetimestampRequiredWhen the shift ends.
breaksarray of objectOptionalPlanned breaks. Left out on create, or when a change moves the start or end, Shiftly plans them from the award.
notesstring, may be nullOptionalThe note on the shift, where the connecting person may see it.

Or send { "data": [ ... ] } with up to 100 items to create several in one request. A refused batch saves nothing.

Request body
{
  "location_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "position_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "employee_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "start_time": "2026-10-06T09:00:00+11:00",
  "end_time": "2026-10-06T09:00:00+11:00",
  "breaks": [
    {
      "offset_minutes": 1,
      "duration_minutes": 1,
      "paid": true
    }
  ],
  "notes": "text"
}
201 response
null
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.
409The error's code is conflict, idempotency_key_reused or request_in_progress. The Errors page describes each code.
422A field is wrong. The field property names it.
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.

Get one shift

GET/v1/shifts/{id}

Permission: roster:read

200 response
{
  "id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "location_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "position_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "employee_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "roster_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "start_time": "2026-10-06T09:00:00+11:00",
  "end_time": "2026-10-06T09:00:00+11:00",
  "status": "unpublished",
  "breaks": [
    {
      "offset_minutes": 1,
      "duration_minutes": 1,
      "paid": true
    }
  ],
  "notes": "text",
  "project_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "paid_hours": 1.5,
  "cost": {
    "total": 1.5,
    "subtotal": 1.5,
    "super": 1.5,
    "allowances": 1.5,
    "position_loading": 1.5,
    "breakdown": [
      {
        "category": null,
        "hours": null,
        "rate": null,
        "cost": null
      }
    ]
  },
  "created_by_app": true,
  "archived": true,
  "created_at": "2026-10-06T09:00:00+11:00",
  "updated_at": "2026-10-06T09:00:00+11:00"
}
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.

Change a shift that has not started

PATCH/v1/shifts/{id}

Permission: roster:write

Request body
FieldTypeRequiredMeaning
position_idstringOptionalThe position being worked.
employee_idstring, may be nullOptionalWho is rostered. Empty for an open shift.
start_timetimestampOptionalWhen the shift starts.
end_timetimestampOptionalWhen the shift ends.
breaksarray of objectOptionalPlanned breaks. Left out on create, or when a change moves the start or end, Shiftly plans them from the award.
notesstring, may be nullOptionalThe note on the shift, where the connecting person may see it.
Request body
{
  "position_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "employee_id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "start_time": "2026-10-06T09:00:00+11:00",
  "end_time": "2026-10-06T09:00:00+11:00",
  "breaks": [
    {
      "offset_minutes": 1,
      "duration_minutes": 1,
      "paid": true
    }
  ],
  "notes": "text"
}
200 response
null
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.
409The error's code is conflict, shift_started, idempotency_key_reused or request_in_progress. The Errors page describes each code.
422A field is wrong. The field property names it.
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.

Delete a shift that has not started

DELETE/v1/shifts/{id}

Permission: roster:write

200 response
{
  "id": "66f1c2a4b3d9e8f7a6b5c4d3",
  "deleted": true
}
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.
409The error's code is conflict, shift_started, idempotency_key_reused or request_in_progress. The Errors page describes each code.
422A field is wrong. The field property names it.
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.

Not available to partner apps

  • POST /v1/shifts/{id}/publish

    Rosters are published in Shiftly, not by partner apps.