API documentation

Overview

The ShiftPlanner REST API allows you to display your shifts on your own website or integrate them into your application. You can query shifts with the same filters available on the All shifts.

The API returns JSON and uses token-based authentication. Each request must include your API token in the request header. Tokens are only available with Premium accounts and can be can be found here.

All active groups are returned, including private groups. Make sure your API token is only shared with trusted parties.

Authentication

Every request must include an Authorization header with a Bearer token:

Authorization: Bearer <your-api-token>

Requests without a valid token receive a 401 Unauthorized response:

{"error": "Invalid or expired API token"}

To request an API token, contact ShiftPlanner support.

Shifts endpoint

GET /:account/api/v1/shifts

Returns a paginated list of shifts for your account. Without filters, the next 12 months of shifts are returned.

Filter parameters

All filter parameters are optional and can be combined freely. Use commas for multiple values, e.g. group_ids=5,2.

Parameter
Type
Description
group_ids
integers (comma-separated)
Filter by one or more group IDs.
months
integers (comma-separated)
Filter by month number (1 = January … 12 = December).
years
integers (comma-separated)
Filter by year, e.g. 2026.
weeks
integers (comma-separated)
Filter by ISO week number (1–53).
days
integers (comma-separated)
Filter by day of week (1 = Sunday, 2 = Monday … 7 = Saturday).
location_ids
integers (comma-separated)
Filter by one or more location IDs.
day
date (YYYY-MM-DD)
Return shifts for a single specific date.
date_from
date (YYYY-MM-DD)
Shifts from (and including) this date. Combine with date_to for a range, even one that spans a year boundary. Can also be used alone for an open end.
date_to
date (YYYY-MM-DD)
Shifts up to (and including) this date. Can also be used alone for an open start.
published
boolean
By default only published shifts are returned. Use published=false to also include shifts that are not yet published.
months and years are combined per calendar year and therefore cannot return a range that spans a year boundary (e.g. December 2026 through January 2027). Use date_from and date_to for that.
weeks uses the ISO week number and correctly handles weeks that span a year boundary (e.g. week 53 only returns the days that actually belong to that ISO week, even when some of them fall in January of the next year). If weeks or days is used without years, results include every matching year but are limited to today onward (no past shifts); add years to also include past occurrences.

Sort order

Results are sorted according to the shift sort order configured in your account settings. The default order is by date and time. When configured to sort by group, results are ordered by date, group name, then time.

Pagination parameters

Parameter
Default
Description
page
1
Page number to retrieve.
per_page
500
Results per page. Maximum is 500.

Response format

The response is JSON with a shifts array and a meta object for pagination.

{
  "shifts": [
    {
      "id": 123,
      "date": "2026-05-01",
      "start_time": "09:00",
      "end_time": "17:00",
      "end_date": "2026-05-01",
      "group": {
        "id": 5,
        "name": "Morning crew"
      },
      "location": {
        "name": "Main hall",
        "address": "Kerkstraat 1, Amsterdam"
      },
      "person": {
        "name": "Jane Doe"
      },
      "publish_date": "2026-04-01",
      "remarks": "Bring your badge",
      "starred": false,
      "cancelled": false,
      "noshow": false
    }
  ],
  "meta": {
    "total": 42,
    "page": 1,
    "per_page": 500,
    "total_pages": 1
  }
}

Field reference

Field
Description
id
Unique shift identifier.
date
Start date of the shift (YYYY-MM-DD).
start_time / end_time
Start and end time (HH:MM, 24-hour).
end_date
End date of the shift. Same as date for single-day shifts.
group
The group this shift belongs to (id + name).
location
Location name and address. null if no location is set.
person
Name of the assigned person. null if the shift is open.
publish_date
Date from which the shift is visible for users (YYYY-MM-DD).
remarks
Optional remarks for this shift.
starred
true if the shift is starred/highlighted.
cancelled
true if the shift has been cancelled.
noshow
true if the assigned person did not show up.

Examples

All upcoming shifts (default)

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts"

Shifts for a specific month and year

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts?months=5&years=2026"

Shifts for a specific group

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts?group_ids=5"

Shifts for multiple groups

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts?group_ids=5,2"

Shifts on a single date

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts?day=2026-05-01"

Shifts for a range spanning a year boundary

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts?date_from=2026-12-01&date_to=2027-01-31"

Paging through results

curl -H "Authorization: Bearer <token>" \
  "https://shiftplanner.org/youraccount/api/v1/shifts?years=2026&page=2&per_page=50"

JavaScript (fetch)

fetch('/youraccount/api/v1/shifts?months=5&years=2026', {
  headers: { 'Authorization': 'Bearer <token>' }
})
.then(r => r.json())
.then(data => console.log(data.shifts));

Error responses

HTTP status
Meaning
200 OK
Request successful.
400 Bad Request
Invalid value for date_from or date_to (expected format: YYYY-MM-DD).
401 Unauthorized
Missing, invalid or expired API token.
404 Not Found
Account not found.