---
title: "Create Shift Block"
method: POST
path: "/scheduling/shift-blocks"
tags: ["scheduling"]
---

# Create Shift Block

`POST /scheduling/shift-blocks`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/scheduling/shift-blocks`
- Auth: HTTP bearer

## Request body

- CreateShiftBlockRequest: Create one shift block on a coverage group. Overlapping another shift of the same group is ALLOWED and expected - a 15-minute handoff is two shifts overlapping by 15 minutes.
  - `group_id` string, uuid, required: The coverage group being scheduled.
  - `shift_date` string, date, required: Center-local calendar date the shift STARTS on.
  - `start_minute` integer, required: Minutes after local midnight of shift_date; multiple of 15.
  - `end_minute` integer, required: Minutes after local midnight of shift_date; multiple of 15, greater than start_minute, and at most start_minute + 1440. Values above 1440 are the overnight case.
  - `operator_ids` string[]: Seated operators in seat order - index 0 is the PRIMARY. May be empty to create an unassigned block.
  - `notes` string, nullable: Free-form notes about the shift.
  - `color` string, nullable: Optional per-shift display color (hex). Null = inherit the coverage group's color.

## Response `200`

Successful Response

- ShiftBlockResponse
  - `block` ShiftBlockModel, required: One shift block: a center-local wall-clock range with an ordered roster.
    - `id` string, uuid, required: The shift ID. Stable across move and resize.
    - `group_id` string, uuid, required: The coverage group being scheduled.
    - `shift_date` string, date, required: Center-local calendar date the shift STARTS on.
    - `start_minute` integer, required: Minutes after local midnight of shift_date (0-1439, multiple of 15).
    - `end_minute` integer, required: Minutes after local midnight of shift_date. Exceeds 1440 for an overnight shift (1560 = 02:00 the next day); at most start_minute + 1440.
    - `start_time` string, required: start_minute as center-local HH:MM.
    - `end_time` string, required: end_minute as center-local HH:MM.
    - `end_day_offset` integer, required: 0 when the shift ends on shift_date, 1 when it runs past midnight.
    - `notes` string, nullable: Free-form notes about the shift.
    - `color` string, nullable: Optional per-shift display color (hex). Null = inherit the coverage group's color.
    - `seats` ShiftSeatModel[], required: Seated operators in seat order - index 0 is the PRIMARY. May be EMPTY: an unassigned block is a real product state (it reads as a coverage gap), not an error.
      - `id` string, uuid, required: The seat's own ID. Stable across reseats the operator survives - the calendar-invite work keys an iCalendar UID on it.
      - `operator_id` string, uuid, required: The seated operator.
      - `seat_order` integer, required: Position in the seat list, contiguous from 0. Seat 0 is the shift's PRIMARY, who bears a miss during the shift.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/35a2a6ebedda?raw)
