---
updatedAt: 2026-04-14T10:02:37.000Z
---

Fetch the complete documentation index at: https://developer.connecteam.com/llms.txt. Use this file to discover all available pages before exploring further.

# Shift Webhook V1 vs V2

This guide covers every scenario where V1 and V2 shift webhooks differ, with complete payload examples you can use as a reference when building your integration.

## What Are V1 and V2?

Shift webhooks support two payload versions that handle **multi-user shifts** (shifts assigned to multiple users) differently:

* **V1** (`webhookVersion: 1`) — Sends a **separate** webhook call for each user in the shift. The `id` represents a user in the shift.
* **V2** (`webhookVersion: 2`) — Sends a **single** webhook call with all users. The `id` represents the shift as a whole. This matches the Scheduler API format.

The version you receive depends on the `webhookVersion` configured in your webhook subscription.

> 🚧 **Important**
>
> V2 webhooks are designed to work with the V2 API. If you are using V2 API endpoints, use V2 webhooks for consistent IDs and behavior.

***

## Quick Comparison

| Aspect                                       | V1                         | V2                              |
| :------------------------------------------- | :------------------------- | :------------------------------ |
| Webhook calls per multi-user shift (3 users) | **3** calls                | **1** call                      |
| What does the `id` represent?                | A user in the shift        | The shift itself                |
| `assignedUserIds` per payload                | 1 user                     | All users                       |
| `openSpots`                                  | Per user                   | Total for the shift             |
| `statuses`                                   | Single user's statuses     | All users' statuses combined    |
| Adding a user to a shift                     | `shift_created` (new user) | `shift_updated` (updated shift) |

***

## Scenarios

### 1. Creating a Single-User Shift

When a shift is assigned to **one user**, V1 and V2 are nearly identical — both send a single webhook call.

**V2 payload:**

```json
{
  "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",
        "createdBy": 9170357,
        "creationTime": 1736760011,
        "updateTime": 1736760011,
        "notes": [],
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

**V1 payload** — same structure, but `webhookVersion: 1` and a different `id`:

```json
{
  "webhookVersion": 1,
  "eventType": "shift_created",
  "...": "...same envelope fields...",
  "data": {
    "shifts": [
      {
        "id": "8a23dacb3c07733b0a849abc",
        "title": "Morning Shift",
        "assignedUserIds": [9170357],
        "...": "...same shift fields..."
      }
    ]
  }
}
```

***

### 2. Creating a Multi-User Shift

**This is the most important difference between V1 and V2.**

**Scenario:** An admin creates "Morning Shift" and assigns it to 3 users: 9170357, 9170358, and 9170359.

#### V2: 1 Webhook Call

All 3 users appear in a **single** payload:

```json
{
  "webhookVersion": 2,
  "eventType": "shift_created",
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736760013,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "6784dacb3c07733b0a849f49",
        "title": "Morning Shift",
        "color": "#4CAF50",
        "assignedUserIds": [9170357, 9170358, 9170359],
        "startTime": 1736924400,
        "endTime": 1736942400,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": false,
        "isPublished": true,
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

#### V1: 3 Separate Webhook Calls

Each user gets their own webhook call with a unique `id`:

**Call 1 of 3 — User 9170357:**

```json
{
  "webhookVersion": 1,
  "eventType": "shift_created",
  "requestId": "a1b2c3d4-0001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736760013,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "8a23dacb3c07733b0a849abc",
        "title": "Morning Shift",
        "assignedUserIds": [9170357],
        "startTime": 1736924400,
        "endTime": 1736942400,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": false,
        "isPublished": true,
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

**Call 2 of 3 — User 9170358:**

```json
{
  "webhookVersion": 1,
  "eventType": "shift_created",
  "requestId": "a1b2c3d4-0002",
  "...": "...same envelope...",
  "data": {
    "shifts": [
      {
        "id": "9b34eadc4d08844c1b950bcd",
        "title": "Morning Shift",
        "assignedUserIds": [9170358],
        "...": "...same shift fields..."
      }
    ]
  }
}
```

**Call 3 of 3 — User 9170359:**

```json
{
  "webhookVersion": 1,
  "eventType": "shift_created",
  "requestId": "a1b2c3d4-0003",
  "...": "...same envelope...",
  "data": {
    "shifts": [
      {
        "id": "ac45fbfd5e19955d2ca61cde",
        "title": "Morning Shift",
        "assignedUserIds": [9170359],
        "...": "...same shift fields..."
      }
    ]
  }
}
```

***

### 3. Creating an Open Shift

Open shifts allow employees to claim available spots.

**V2 payload:**

```json
{
  "webhookVersion": 2,
  "eventType": "shift_created",
  "requestId": "open-shift-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736760013,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "7894dacb3c07733b0a849f50",
        "title": "Open Morning Shift",
        "color": "#FF9800",
        "assignedUserIds": [],
        "startTime": 1736924400,
        "endTime": 1736942400,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": true,
        "isPublished": true,
        "isRequireAdminApproval": false,
        "openSpots": 5,
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

In V2, `openSpots` represents the **total** available spots for the shift. As employees claim spots, `assignedUserIds` grows and `openSpots` decreases.

***

### 4. Updating a Shift

When a shift is updated (title, time, status change, etc.), both V1 and V2 send `shift_updated`. The payload contains the **current state** of the shift after the update.

**V2 payload:**

```json
{
  "webhookVersion": 2,
  "eventType": "shift_updated",
  "requestId": "update-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736762000,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "6784dacb3c07733b0a849f49",
        "title": "Morning Shift - Updated",
        "color": "#4CAF50",
        "assignedUserIds": [9170357, 9170358, 9170359],
        "startTime": 1736924400,
        "endTime": 1736946000,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": false,
        "isPublished": true,
        "updateTime": 1736762000,
        "statuses": [
          {
            "statusId": "st-001",
            "status": "accepted",
            "assignedUserId": 9170357,
            "creatingUserId": 9170357,
            "creationTime": 1736760100
          },
          {
            "statusId": "st-002",
            "status": "rejected",
            "assignedUserId": 9170358,
            "creatingUserId": 9170358,
            "creationTime": 1736760200
          }
        ],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

**Key V2 details for multi-user shifts:**

* `assignedUserIds` — all current users in the shift
* `statuses` — combined from all users (use the `assignedUserId` field on each status to identify which user it belongs to)
* `updateTime` — the most recent update across all users

***

### 5. Deleting a Shift

When a shift is deleted, the payload contains only the IDs — no full shift objects.

**V2 payload:**

```json
{
  "webhookVersion": 2,
  "eventType": "shift_deleted",
  "requestId": "delete-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736763000,
  "schedulerId": 9454799,
  "data": {
    "ids": ["6784dacb3c07733b0a849f49"]
  }
}
```

V2 returns **1 shift ID** regardless of how many users were assigned.

**V1 payload:**

```json
{
  "webhookVersion": 1,
  "eventType": "shift_deleted",
  "requestId": "delete-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736763000,
  "schedulerId": 9454799,
  "data": {
    "ids": [
      "8a23dacb3c07733b0a849abc",
      "9b34eadc4d08844c1b950bcd",
      "ac45fbfd5e19955d2ca61cde"
    ]
  }
}
```

V1 returns **one ID per user** in the shift. A 3-user shift deletion produces 3 IDs.

***

### 6. Removing a User from a Multi-User Shift

When a user is removed from a shift **but other users remain**, the system sends **two** separate webhooks.

**Scenario:** A shift has 3 users (9170357, 9170358, 9170359). An admin removes user 9170359.

#### Webhook 1 — `shift_updated`

Shows the shift with the updated user list:

```json
{
  "webhookVersion": 2,
  "eventType": "shift_updated",
  "requestId": "partial-delete-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736763000,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "6784dacb3c07733b0a849f49",
        "title": "Morning Shift",
        "assignedUserIds": [9170357, 9170358],
        "startTime": 1736924400,
        "endTime": 1736942400,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": false,
        "isPublished": true,
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

Notice `assignedUserIds` now has 2 users instead of 3.

#### Webhook 2 — `shift_deleted`

Reports the removal. The content differs by version:

**V2:**

```json
{
  "webhookVersion": 2,
  "eventType": "shift_deleted",
  "requestId": "partial-delete-002",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736763000,
  "schedulerId": 9454799,
  "data": {
    "ids": []
  }
}
```

> 📘 **Why is `ids` empty in V2?**
>
> In V2, the shift still exists (with 2 remaining users), so no shift ID is deleted. V2 only includes an ID in `shift_deleted` when the **entire shift** is removed. For partial user removals, the `shift_updated` webhook above is the primary notification.

**V1:**

```json
{
  "webhookVersion": 1,
  "eventType": "shift_deleted",
  "requestId": "partial-delete-002",
  "...": "...same envelope...",
  "data": {
    "ids": [
      "ac45fbfd5e19955d2ca61cde"
    ]
  }
}
```

V1 includes the ID for the removed user.

> 🚧 **Important**
>
> This dual-webhook pattern (`shift_updated` + `shift_deleted`) **only** happens when some users remain on the shift. If you delete the entire shift (all users), only `shift_deleted` fires.

***

### 7. Adding a User to an Existing Shift

When a new user is added to a shift, V1 and V2 send **different event types**.

**Scenario:** A shift has 2 users (9170357, 9170358). User 9170360 is added.

#### V2: `shift_updated`

V2 treats this as an update to the existing shift:

```json
{
  "webhookVersion": 2,
  "eventType": "shift_updated",
  "requestId": "add-user-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736764000,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "6784dacb3c07733b0a849f49",
        "title": "Morning Shift",
        "assignedUserIds": [9170357, 9170358, 9170360],
        "startTime": 1736924400,
        "endTime": 1736942400,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": false,
        "isPublished": true,
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

#### V1: `shift_created`

V1 treats adding a user as a new entry and sends `shift_created` for the added user only:

```json
{
  "webhookVersion": 1,
  "eventType": "shift_created",
  "requestId": "add-user-001",
  "company": "your_company_id",
  "activityType": "shift",
  "eventTimestamp": 1736764000,
  "schedulerId": 9454799,
  "data": {
    "shifts": [
      {
        "id": "bd56gcge6f2aa66e3db72def",
        "title": "Morning Shift",
        "assignedUserIds": [9170360],
        "startTime": 1736924400,
        "endTime": 1736942400,
        "timezone": "Asia/Jerusalem",
        "allDay": false,
        "isOpenShift": false,
        "isPublished": true,
        "statuses": [],
        "breaks": [],
        "shiftDetails": { "shiftLayers": [] },
        "customFields": []
      }
    ]
  }
}
```

> 🚧 **V1 does not notify about existing users**
>
> When a user is added, V1 only sends `shift_created` for the **new** user. Existing users are not included.

***

## Migration Checklist

If you are upgrading from V1 to V2 webhooks:

* [ ] **Handle multiple users per payload** — V2 payloads can include multiple users in `assignedUserIds`. Update any code that assumes 1 user per webhook.
* [ ] **Expect fewer webhook calls** — A shift with N users triggers 1 V2 call instead of N V1 calls.
* [ ] **Use the shift ID directly** — V2 returns the same ID format as the Scheduler API.
* [ ] **Handle the update+delete pattern** — When a user is removed from a shift, you receive both `shift_updated` (remaining users) and `shift_deleted`. The V2 `shift_deleted` may have empty `ids` for partial removals.
* [ ] **Check for aggregated `openSpots`** — V2 reports the total open spots for the shift.
* [ ] **Parse combined `statuses`** — V2 includes statuses from all users. Use the `assignedUserId` field on each status to identify the user.
* [ ] **Adding user = `shift_updated`** — In V2, adding a user triggers `shift_updated` (not `shift_created`). Update your event routing logic accordingly.

***

[← Scheduler Webhook](scheduler-webhook)

[API Reference](https://developer.connecteam.com/reference/)