Endpoint-by-Endpoint Reference
This page covers, endpoint by endpoint, what changes between V1 and V2 on a JS Vision-migrated company. All paths are relative to https://api.connecteam.com/scheduler/{v1|v2}/schedulers/{schedulerId}.
ReminderOn non-Vision companies, every V2 endpoint returns
403. The tables and examples below describe behavior on a migrated company.
GET /shifts — list shifts
GET /shifts — list shifts| V1 | V2 | |
|---|---|---|
| Result shape | One row per user assignment (slot) | One row per base shift |
assignedUserIds length | 0 or 1 | 0, 1, or more |
shiftId query filter accepts | Slot ID, or pre-migration legacy ID | Base ID |
| Pagination unit | Slot | Base shift |
limit semantics | Up to N slots | Up to N base shifts |
startTime, endTime, isOpenShift, isPublished, isRequireAdminApproval, jobId, assignedUserIds, title, sort, order, limit, and offset are identical between V1 and V2.
V1 request:
curl --request GET \
--url 'https://api.connecteam.com/scheduler/v1/schedulers/{schedulerId}/shifts?startTime=1736899200&endTime=1737504000&limit=10' \
--header 'X-API-KEY: YOUR_API_KEY'V2 request (same params, different path):
curl --request GET \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts?startTime=1736899200&endTime=1737504000&limit=10' \
--header 'X-API-KEY: YOUR_API_KEY'
Pagination caveatIf you have 100 base shifts each with 3 users:
- V1 with
limit=10returns the first 10 slots, which may cover only 3–4 distinct base shifts.- V2 with
limit=10returns the first 10 base shifts (10 aggregated objects).
GET /shifts/{shiftId} — single shift
GET /shifts/{shiftId} — single shift| V1 | V2 | |
|---|---|---|
| Path ID accepts | Slot ID, or pre-migration legacy ID | Base ID only — slot ID returns 400 |
| Response | The specific slot the ID points to | Aggregated base shift (all slots collapsed) |
V1 request (slot ID in path):
curl --request GET \
--url 'https://api.connecteam.com/scheduler/v1/schedulers/{schedulerId}/shifts/6784dacb3c07733b0a849f49:7a4e8a18-...' \
--header 'X-API-KEY: YOUR_API_KEY'V2 request (base ID in path):
curl --request GET \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts/6784dacb3c07733b0a849f49' \
--header 'X-API-KEY: YOUR_API_KEY'POST /shifts — create shifts
POST /shifts — create shifts| V1 | V2 | |
|---|---|---|
assignedUserIds length | 0 or 1 (more → 400) | Any |
openSpots > 1 on an open shift | 400 | Allowed (1 ≤ openSpots ≤ 100) |
| Group-shift creation in one call | Not possible | One object with multiple assignedUserIds |
| Created group-shift response | One object per user (slot IDs) | One aggregated object (base ID) |
V2: create a group shift with three users:
curl --request POST \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts' \
--header 'X-API-KEY: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '[
{
"startTime": 1736924400,
"endTime": 1736953200,
"title": "Morning Shift",
"assignedUserIds": [9170357, 9170358, 9170359],
"isPublished": true
}
]'V2: create an open shift with 5 spots:
curl --request POST \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts' \
--header 'X-API-KEY: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '[
{
"startTime": 1736924400,
"endTime": 1736953200,
"title": "Event Coverage",
"isOpenShift": true,
"openSpots": 5,
"isPublished": true
}
]'
V1 cannot create multi-user or multi-spot shiftsOn V1,
assignedUserIdsof length > 1 returns400 ("V1 supports at most one assigned user per shift")andopenSpots != 1also returns400. To create a multi-user or multi-spot shift on a migrated company, you must use V2.
PUT /shifts — update shifts
PUT /shifts — update shifts| V1 | V2 | |
|---|---|---|
shiftId in body accepts | Slot ID, or pre-migration legacy ID | Base ID only |
isEditForAllUsers: true | 400 ("not supported in V1") | Allowed |
openSpots in body | 400 ("not supported in V1 update") | Allowed |
Multiple assignedUserIds | 400 ("V1 supports at most one assigned user per shift") | Allowed |
Default mode for a non-open group when no assignedUserIds is sent | Edits the specific slot only | Implicit ALL_USERS — applies to every user in the group |
createdShifts / deletedShiftIds in response | Always empty | Populated when users change |
Why V2's "implicit ALL_USERS" mattersIn V2 you're addressing a base shift by base ID. When you update a title, time, location, or job, the API assumes you want the change to apply to every user in the group — because that's the natural mental model when you only see one object per group. You don't need to set
isEditForAllUsers: truefor property changes; it's the default. This is one of the main reasons V2 is easier to use for management dashboards and bulk operations.
Update a group's title in one call (V2)
curl --request PUT \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts' \
--header 'X-API-KEY: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '[
{
"shiftId": "6784dacb3c07733b0a849f49",
"title": "Updated Title"
}
]'All users on the group see the new title.
Edit one user out of a group (V2)
Set isEditForAllUsers: false and pass assignedUserIds with the single user you want to change:
curl --request PUT \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts' \
--header 'X-API-KEY: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '[
{
"shiftId": "6784dacb3c07733b0a849f49",
"isEditForAllUsers": false,
"assignedUserIds": [9170357],
"title": "Updated only for this user"
}
]'The API detaches that user's slot from the group and applies your edits only to them; the other users' slots stay untouched.
createdShifts and deletedShiftIds in the response
createdShifts and deletedShiftIds in the responseWhen a V2 PUT changes the user set on a group (assignedUserIds), the API may need to add or remove slots under the same base shift. These show up in the response alongside the edited shifts:
{
"data": {
"shifts": [ /* shifts whose properties changed */ ],
"createdShifts": [ /* slots added because users were added to the group */ ],
"deletedShiftIds": [ /* slot IDs removed because users were removed from the group */ ]
}
}
V1 never returns non-emptycreatedShifts/deletedShiftIdsV1 never restructures a group from a single
PUT, so these arrays are always empty on V1. If your code reads them, it will only ever see content on V2.
DELETE /shifts and DELETE /shifts/{shiftId}
DELETE /shifts and DELETE /shifts/{shiftId}| V1 | V2 | |
|---|---|---|
| IDs accepted | Slot IDs, or pre-migration legacy IDs | Base IDs only |
| Delete by base ID | Not accepted | Removes every slot under that base shift |
| Delete by slot ID | Removes that single slot only | 400 Bad Request |
| Response IDs | Slot IDs that were removed | Base IDs that were removed |
V2: delete an entire group in one call:
curl --request DELETE \
--url 'https://api.connecteam.com/scheduler/v2/schedulers/{schedulerId}/shifts/6784dacb3c07733b0a849f49' \
--header 'X-API-KEY: YOUR_API_KEY'V1: delete only one user's slot from a group:
curl --request DELETE \
--url 'https://api.connecteam.com/scheduler/v1/schedulers/{schedulerId}/shifts/6784dacb3c07733b0a849f49:7a4e8a18-...' \
--header 'X-API-KEY: YOUR_API_KEY'The group stays intact for the other users.
Removing one user from a group on V2V2 has no direct "delete one user" operation. Use
PUTinstead, withassignedUserIdsset to the users who should remain. The API will detach the removed user's slot and list it indeletedShiftIds.
Validation rules that differ between V1 and V2
Even though the request schema is the same, V1 validators are stricter to preserve legacy behavior.
V1-only rejections on a migrated company
| Field / situation | V1 rule | Error code |
|---|---|---|
assignedUserIds length > 1 | Rejected | 400 ("V1 supports at most one assigned user per shift") |
openSpots != 1 on create | Rejected | 400 |
openSpots present on update | Rejected | 400 ("not supported in V1 update") |
isEditForAllUsers: true | Rejected | 400 ("not supported in V1") |
Plain BSON shiftId (no :) on a migrated company | Rejected unless it's a known legacy ID | 400 ("shift id is invalid") |
| Mixed slot/legacy IDs in one request | Rejected | 400 ("must be all new format ids ... or all legacy ids") |
V2-only rejections
| Field / situation | V2 rule | Error code |
|---|---|---|
Slot-shaped shiftId (contains :) | Rejected | 400 ("shift id is invalid") |
| Any V2 endpoint on a non-Vision company | Rejected | 403 |
Pagination on a migrated company
This is the most common pitfall when an existing V1 integration starts using V2.
V1 + Vision paginates by slot, with a deterministic secondary sort on the slot ID. If you have base shifts with multiple users, limit controls how many user-rows come back — not how many distinct shifts.
limit=10 → up to 10 rows, each row = one user assignment
↑ this may include several rows that share a base ID prefixV2 + Vision paginates by base shift. Each row in the response is one aggregated shift.
limit=10 → up to 10 aggregated shifts, each with assignedUserIds: [...]
Pagination loop pattern (identical for V1 and V2)Pass
paging.offsetfrom each response back as theoffsetquery parameter on the next request. Stop when the response returns fewer items thanlimit.
Updated about 19 hours ago
