Scheduler webhook
The Scheduler webhook sends real-time notifications whenever shifts or user availability change in your schedule. Use these webhooks to keep your systems in sync with schedule changes without polling.
Supported Events
| Event Type | Trigger | Data Key |
|---|---|---|
shift_created | A new shift is created | data.shifts |
shift_updated | A shift is modified (title, time, users, status, etc.) | data.shifts |
shift_deleted | A shift is deleted | data.ids |
availability_status_created | A user submits an availability or unavailability entry | availabilityStatuses |
availability_status_deleted | A user's availability entry is removed | availabilityStatuses |
Webhook Envelope
Every scheduler webhook payload shares the same top-level structure. Here is a complete example:
{
"webhookVersion": 1,
"eventType": "shift_created",
"requestId": "b28d441c-e416-4c11-adb0-c8e0364ff29c",
"company": "your_company_id",
"activityType": "shift",
"eventTimestamp": 1736760013,
"schedulerId": 9454799,
"data": {
"shifts": [...]
}
}| Field | Type | Description |
|---|---|---|
webhookVersion | integer | The webhook payload version — 1 or 2. See Shift Webhook V1 vs V2 for details. |
eventType | string | The event that triggered this webhook (e.g. shift_created, shift_updated, shift_deleted) |
requestId | string | Unique identifier for this webhook delivery. Use for deduplication. |
company | string | Your company identifier |
activityType | string | "shift" for shift events, "shift_scheduler" for availability events |
eventTimestamp | integer | Unix timestamp of when the event occurred |
schedulerId | integer | The ID of the schedule this event belongs to |
data | object | The event payload — structure depends on the event type (see below) |
Optional fieldsFields marked as optional below may be absent from the payload (not
null). Design your parser to handle missing keys gracefully.
Webhook Versions: V1 & V2
Shift webhooks support two payload versions. The version you receive depends on the webhookVersion configured in your webhook subscription.
V1 (webhookVersion: 1) | V2 (webhookVersion: 2) | |
|---|---|---|
| Multi-user shifts | One webhook call per user. A 3-user shift = 3 calls. | One webhook call per shift. A 3-user shift = 1 call. |
What does id represent? | A user in the shift | The shift itself |
assignedUserIds | Single user per payload | All assigned users in one array |
openSpots | Per user | Total for the shift |
statuses | Single user's statuses | Combined from all users |
V2 webhooks are designed to work with the V2 API. Use V2 webhooks for consistent IDs and behavior with API endpoints.
For detailed V1 vs V2 examplesSee Shift Webhook V1 vs V2 for side-by-side payload comparisons covering multi-user shifts, open shifts, user removal, and every other scenario.
Shift Events
shift_created
Sent when one or more new shifts are created. The data.shifts array contains the full shift object(s).
{
"webhookVersion": 2,
"eventType": "shift_created",
"requestId": "b28d441c-e416-4c11-adb0-c8e0364ff29c",
"company": "your_company_id",
"activityType": "shift",
"eventTimestamp": 1736760013,
"schedulerId": 9454799,
"data": {
"shifts": [
{
"id": "6784dacb3c07733b0a849f49",
"title": "Morning Shift",
"color": "#4CAF50",
"assignedUserIds": [9170357],
"startTime": 1736924400,
"endTime": 1736942400,
"timezone": "Asia/Jerusalem",
"allDay": false,
"isOpenShift": false,
"isPublished": true,
"isRequireAdminApproval": false,
"jobId": "d4ad7232-576f-2ff6-c57d-8240f1089b00",
"locationData": {
"isReferencedToJob": true,
"gps": {
"address": "Times Square, Manhattan, NY, USA",
"longitude": -73.9855426,
"latitude": 40.7579747
}
},
"createdBy": 9170357,
"creationTime": 1736760011,
"updateTime": 1736760011,
"notes": [],
"statuses": [],
"breaks": [
{
"id": "brk-001",
"name": "Lunch Break",
"type": "unpaid",
"startTime": 240,
"duration": 30
}
],
"shiftDetails": {
"shiftLayers": [
{
"id": "layer-dept",
"title": "Department",
"value": {
"id": "val-kitchen",
"displayName": "Kitchen"
}
}
]
},
"customFields": [
{
"customFieldId": 42,
"name": "Uniform Color",
"type": "str",
"value": "Blue"
}
]
}
]
}
}shift_updated
Sent when a shift is modified. Same structure as shift_created but with eventType: "shift_updated". The shift objects reflect the current state after the update.
{
"webhookVersion": 2,
"eventType": "shift_updated",
"requestId": "c39e552d-f527-5d22-bdc1-d9f1475gg30d",
"company": "your_company_id",
"activityType": "shift",
"eventTimestamp": 1736762000,
"schedulerId": 9454799,
"data": {
"shifts": [
{
"id": "6784dacb3c07733b0a849f49",
"title": "Morning Shift - Updated",
"color": "#4CAF50",
"assignedUserIds": [9170357, 9170358],
"startTime": 1736924400,
"endTime": 1736946000,
"timezone": "Asia/Jerusalem",
"allDay": false,
"isOpenShift": false,
"isPublished": true,
"updateTime": 1736762000,
"notes": [],
"statuses": [
{
"statusId": "st-001",
"status": "accepted",
"assignedUserId": 9170357,
"creatingUserId": 9170357,
"creationTime": 1736760100
},
{
"statusId": "st-002",
"status": "rejected",
"assignedUserId": 9170358,
"creatingUserId": 9170358,
"creationTime": 1736760200,
"note": "Cannot make it"
}
],
"breaks": [],
"shiftDetails": {
"shiftLayers": []
},
"customFields": []
}
]
}
}shift_deleted
Sent when a shift is deleted. The data object contains only the IDs of deleted shifts — no full shift objects.
{
"webhookVersion": 2,
"eventType": "shift_deleted",
"requestId": "5b496380-2053-414e-9a9e-983efefbb1b2",
"company": "your_company_id",
"activityType": "shift",
"eventTimestamp": 1736760206,
"schedulerId": 9454799,
"data": {
"ids": [
"6784dacb3c07733b0a849f49"
]
}
}
V1 vs V2 differenceIn V2,
idscontains one ID per shift.
In V1,idscontains one ID per user — so deleting a 3-user shift returns 3 IDs.
See Shift Webhook V1 vs V2 for details.
Shift Payload Fields
These fields appear in each shift object inside data.shifts for shift_created and shift_updated events.
| Field | Type | Present | Description |
|---|---|---|---|
id | string | Always | Unique shift identifier |
title | string | Always | Shift name |
color | string | Always | Shift color (hex string or empty) |
assignedUserIds | integer[] | Always | User IDs assigned to the shift |
startTime | integer | Always | Unix timestamp of shift start |
endTime | integer | Always | Unix timestamp of shift end |
timezone | string | Always | IANA timezone (e.g. "America/New_York") |
allDay | boolean | Always | Whether this is an all-day shift |
isOpenShift | boolean | Always | Whether this is an open shift (claimable by employees) |
isPublished | boolean | Always | Whether the shift is visible to employees |
isRequireAdminApproval | boolean | Optional | Whether open-shift claims require admin approval |
jobId | string | Optional | Associated job ID |
locationData | object | Optional | Location information — see below |
createdBy | integer | Optional | User ID of the shift creator |
creationTime | integer | Optional | Unix timestamp of creation |
updateTime | integer | Optional | Unix timestamp of last update |
openSpots | integer | Optional | Number of open spots. Only present when isOpenShift is true. |
notes | array | Always | Shift notes — see below |
statuses | array | Always | User statuses for this shift — see below |
breaks | array | Always | Scheduled breaks — see below |
shiftDetails | object | Always | Additional details including shift layers — see below |
customFields | array | Always | Custom field values — see below |
locationData
Location information attached to the shift.
{
"isReferencedToJob": true,
"gps": {
"address": "Times Square, Manhattan, NY, USA",
"longitude": -73.9855426,
"latitude": 40.7579747
}
}| Field | Type | Description |
|---|---|---|
isReferencedToJob | boolean | Whether the location is inherited from the associated job |
gps | object | GPS coordinates with address (string), longitude (number), latitude (number) |
statuses
Each entry represents a user's response status for the shift. In V2, this array includes statuses from all assigned users.
{
"statusId": "abc123",
"status": "accepted",
"assignedUserId": 9170357,
"creatingUserId": 9170357,
"creationTime": 1736760013,
"updateTime": 1736760100,
"note": "On my way",
"gps": {
"address": "123 Main St",
"longitude": -73.9855,
"latitude": 40.7579
}
}| Field | Type | Description |
|---|---|---|
statusId | string | Unique status record ID |
status | string | One of: accepted, rejected, checked_in, completed, claimed, claim_requested, unclaimed, unclaim_requested, cancel_claim_request, reset |
assignedUserId | integer | The user this status belongs to |
creatingUserId | integer | User who created the status |
modifyingUserId | integer | User who last modified the status (optional) |
creationTime | integer | Unix timestamp of status creation (optional) |
updateTime | integer | Unix timestamp of last status update (optional) |
note | string | Status note text (optional) |
attachments | string[] | Attachment identifiers (optional) |
gps | object | GPS data at time of status change (optional) |
breaks
Scheduled break periods within the shift.
{
"id": "brk-001",
"name": "Lunch Break",
"type": "unpaid",
"startTime": 720,
"duration": 30
}| Field | Type | Description |
|---|---|---|
id | string | Unique break ID |
name | string | Break name |
type | string | "paid" or "unpaid" |
startTime | integer | Minutes from the start of the day (e.g. 720 = 12:00 PM). Optional — may be absent for flexible breaks. |
duration | integer | Break duration in minutes |
notes
Shift notes attached by admins. Notes use snake_case field names (unlike the rest of the payload which uses camelCase).
Three note types exist, identified by the type field:
HTML note:
{
"type": "html",
"html": "<p>Remember to bring safety equipment</p>"
}File attachment:
{
"type": "file",
"url": "https://files.example.com/instructions.pdf",
"name": "instructions.pdf"
}Image album:
{
"type": "album",
"album": [
{ "url": "https://files.example.com/photo1.jpg" },
{ "url": "https://files.example.com/photo2.jpg" }
]
}shiftDetails
Additional metadata about the shift, primarily shift layer assignments.
{
"shiftLayers": [
{
"id": "layer-dept",
"title": "Department",
"value": {
"id": "val-kitchen",
"displayName": "Kitchen"
}
}
]
}| Field | Type | Description |
|---|---|---|
shiftLayers | array | Shift layer assignments. Each entry has id (layer definition ID), title (display name), and value (selected instance with id and displayName) |
shiftSource | string | Source identifier for the shift (optional — only present when the shift was created from an external source) |
customFields
Custom field values set on this shift. Currently supports str (text) and dropdown types.
Text custom field:
{
"customFieldId": 42,
"name": "Uniform Color",
"type": "str",
"value": "Blue"
}Dropdown custom field:
{
"customFieldId": 43,
"name": "Skill Level",
"type": "dropdown",
"value": [
{ "id": 1, "value": "Advanced" }
]
}| Field | Type | Description |
|---|---|---|
customFieldId | integer | Custom field definition ID |
name | string | Custom field label |
type | string | Field type — "str" or "dropdown" |
value | varies | Text string for str type, or array of { "id", "value" } objects for dropdown type |
Availability Events
Availability webhooks notify you when users submit or remove their availability status. These events are not affected by webhook versioning — they always use the same format.
availability_status_created
{
"eventType": "availability_status_created",
"requestId": "2907af4d-dae5-4778-b673-d2e437701b9c",
"company": "your_company_id",
"activityType": "shift_scheduler",
"eventTimestamp": 1736760518,
"schedulerId": 9454799,
"availabilityStatuses": [
{
"id": "6784dcc39585f9dc60f7a6cb",
"type": "unavailable",
"userId": 9170357,
"start": {
"timestamp": 1736935200,
"timezone": "Asia/Jerusalem"
},
"end": {
"timestamp": 1736935200,
"timezone": "Asia/Jerusalem"
},
"isAllDay": true,
"note": "Doctor appointment"
}
],
"isAdminAction": false
}availability_status_deleted
{
"eventType": "availability_status_deleted",
"requestId": "bc16a835-c3c6-4a94-83bb-694cf0c138b8",
"company": "your_company_id",
"activityType": "shift_scheduler",
"eventTimestamp": 1736760523,
"schedulerId": 9454799,
"availabilityStatuses": [
{
"id": "6784dcc39585f9dc60f7a6cb",
"type": "unavailable",
"userId": 9170357,
"start": {
"timestamp": 1736935200,
"timezone": "Asia/Jerusalem"
},
"end": {
"timestamp": 1736935200,
"timezone": "Asia/Jerusalem"
},
"isAllDay": true,
"note": ""
}
],
"isAdminAction": false
}Availability Payload Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique availability record ID |
type | string | "available" or "unavailable" |
userId | integer | The user this status belongs to |
start | object | Start time with timestamp (Unix) and timezone (IANA) |
end | object | End time with timestamp (Unix) and timezone (IANA) |
isAllDay | boolean | Whether this covers the entire day |
note | string | Optional note from the user |
isAdminAction | boolean | true if set by an admin on behalf of the user |
Updated 13 days ago
