Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
    • Task Scheduling
  • Platform
Start Free Trial
  • Employee Shift Scheduling
  • Employee resource constraints
  • Employee groups
  • latest
    • latest
    • 1.35.x
    • 1.34.x

Employee Shift Scheduling

    • Introduction
    • Getting started: Hello world
    • Lessons overview
      • Lesson 1
      • Lesson 2
      • Lesson 3
      • Lesson 4
      • Interlude 1: Basic demo data
    • User guide
      • Terminology
      • Use case guide
      • Scheduling API concepts
      • Integration
      • Constraints
      • Using the API
        • Using the OpenAPI spec
        • API tooling
      • Demo datasets
      • Input datasets
        • Model configuration
        • Model input
        • Planning window
      • Planning window
      • Time zones and Daylight Saving Time (DST)
      • Tags and tag types
      • Input validation
      • Output datasets
        • Metadata
        • Model output
        • Input metrics
        • Key performance indicators (KPIs)
      • Metrics and optimization goals
      • Score analysis
      • Visualization
      • Efficiency X-Ray
      • Assignability analysis
    • Employee resource constraints
      • Employee availability and preferences
        • Employee availability
        • Employee preferences
      • Employee contracts
      • Employee priority
      • Pairing employees
      • Employee groups
      • Shift travel and locations
      • Shift Breaks
      • Employee activation
      • Work limits
        • Minutes worked per period
        • Minutes worked in a rolling window
        • Minutes logged per period
        • Days worked per period
        • Days worked in a rolling window
        • Consecutive days worked
        • Shifts worked per period
        • Shifts worked in a rolling window
        • Weekend minutes worked per period
        • Weekends worked per period
        • Weekends worked in a rolling window
        • Consecutive weekends worked
        • Consecutive shifts worked
      • Time off
        • Days off per period
        • Consecutive days off per period
        • Consecutive days off in a rolling window
        • Consecutive minutes off in a rolling window
        • Shifts to avoid close to day off requests
        • Consecutive weekends off per period
      • Shift rotations and patterns
        • Shift rotations
        • Single day shift sequence patterns
        • Minimize gaps between shifts
        • Multi-day shift sequence patterns
        • Daily shift pairings
        • Overlapping shifts
        • Shift start times differences
        • Minutes between shifts
      • Shift type diversity
        • Shift tag types
        • Shift types worked per period
        • Unique tags per period
      • Fairness
        • Balance time worked
        • Balance shift count
    • Shift service constraints
      • Alternative shifts
      • Cost management
        • Cost groups
        • Employee rates
      • Demand-based scheduling
      • Priority and optional shifts
      • Skills and risk factors
      • Shift assignments
        • Shift selection
        • Employee selection
    • Manual intervention
    • Recommendations
    • Real-time planning
    • Scenarios
      • Configuring labor law compliance
      • Configuring employee well-being
      • Self-rostering and optimization
    • Changelog
    • Upgrade to the latest version
    • Feature requests

Employee groups

employeeGroups is a preview feature and subject to change.

Employee groups are declared in the top-level employeeGroups collection, for cases where a set of employees must be considered together as group rather than individually or as a pair. Each group has an explicit membership, split into requiredEmployees and preferredEmployees:

  • requiredEmployees don’t require any other group member to be present when they work, but prefer other members of the group to also be present.

  • preferredEmployees require at least one of the group’s requiredEmployees to be present when they work, and prefer other employees of the group to also be present.

A common example is a carpooling arrangement: a driver (requiredEmployees) can drive alone if needed, but passengers (preferredEmployees) can’t be scheduled without a driver.

{
  "employees": [
    { "id": "Ann" },
    { "id": "Beth" },
    { "id": "Carl" }
  ],
  "employeeGroups": [
    {
      "id": "CAR 1",
      "requiredEmployees": [ "Ann" ],
      "preferredEmployees": [ "Beth", "Carl" ]
    }
  ]
}

In this example, Ann is the required driver of the CAR 1 employee group, and Beth and Carl are preferred passengers. Beth and Carl can each only be assigned to a shift when Ann also has an overlapping shift. Ann can be assigned to any shift on her own, but Timefold prefers to schedule her together with Beth or Carl when possible.

  • Requiring a shared tag type
  • Limiting how many different shift hours a group can work per day

Requiring a shared tag type

Use commonTagType on an employee group, when the group’s members must not only work together but must also cover shifts in the same tag category, such as the same route, location, or department.

commonTagType takes a reference to a tag type defined in the tagTypes collection. When set, all working members of the group must have a concurrent shift with the same tag belonging to that tag type.

{
  "tagTypes": [
    { "id": "Zone A" }
  ],
  "tags": [
    { "id": "Location 1", "tagType": "Zone A" },
    { "id": "Location 2", "tagType": "Zone A" }
  ],
  "employees": [
    { "id": "Ann" },
    { "id": "Beth" }
  ],
  "employeeGroups": [
    {
      "id": "CAR 1",
      "requiredEmployees": [ "Ann" ],
      "preferredEmployees": [ "Beth" ],
      "commonTagType": "Zone A"
    }
  ]
}

In this example, Ann and Beth are both members of the CAR 1 employee group, which specifies commonTagType: Zone A. Beth can only be assigned to shifts with a tag belonging to Zone A where Ann is also assigned, and both must share the same Zone A tag when they work together.

The Grouped employees don’t work shifts with common tags hard constraint is invoked when two employees who belong to the same employee group are assigned to overlapping shifts that don’t share a common shift tag of the required tag type, meaning the grouped employees are working at the same time but not on shifts that share the tag (e.g. location or department) they are supposed to have in common.

The constraint adds a hard penalty to the dataset score that is calculated by the number of overlapping minutes between the two conflicting shifts, incentivizing Timefold to schedule grouped employees onto concurrent shifts that share the required common tag, so they end up working together at the same place rather than being split across differently tagged shifts.

Declare tags and tag types in the tagTypes and tags top-level collections so that commonTagType resolves correctly. See Tags and tag types for details.

Requiring a shared tag type example

In the following example, Ann and Beth share a car and must cover shifts on the same route. Two shifts are available in Zone A and one in Zone B. Ann is the required driver of the CAR 1 employee group; Beth is a preferred passenger. The solver assigns both Ann and Beth to the Zone A shifts and assigns Carl to the Zone B shift.

employee groups required tag type

  • Input

  • Output

Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/employee-scheduling/v1/schedules [email protected]
{
  "config": {
    "run": {
      "name": "Required tag type pairing example"
    }
  },
  "modelInput": {
    "tagTypes": [
      {
        "id": "Zone"
      }
    ],
    "tags": [
      {
        "id": "Zone A",
        "tagType": "Zone"
      },
      {
        "id": "Zone B",
        "tagType": "Zone"
      }
    ],
    "contracts": [
      {
        "id": "fullTimeContract",
        "periodRules": [
          {
            "id": "Max8HoursPerDayFullTime",
            "period": "DAY",
            "minutesWorkedLimit": {
              "minutesWorkedMax": 480
            }
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "fullTimeContract"
        ],
        "tags": [
          "CAR 1",
          "CAR 1 Driver"
        ]
      },
      {
        "id": "Beth",
        "contracts": [
          "fullTimeContract"
        ],
        "tags": [
          "CAR 1",
          "CAR 1 Passenger"
        ]
      },
      {
        "id": "Carl",
        "contracts": [
          "fullTimeContract"
        ]
      }
    ],
    "employeeGroups": [
      {
        "id": "CAR 1 group",
        "requiredEmployees": [
          "Ann"
        ],
        "preferredEmployees": [
          "Beth"
        ],
        "commonTagType": "Zone"
      }
    ],
    "shifts": [
      {
        "id": "Tue A 1",
        "start": "2027-02-02T06:00:00Z",
        "end": "2027-02-02T14:00:00Z",
        "tags": [
          "Zone A"
        ]
      },
      {
        "id": "Tue A 2",
        "start": "2027-02-02T06:00:00Z",
        "end": "2027-02-02T14:00:00Z",
        "tags": [
          "Zone A"
        ]
      },
      {
        "id": "Tue B 1",
        "start": "2027-02-02T06:00:00Z",
        "end": "2027-02-02T14:00:00Z",
        "tags": [
          "Zone B"
        ]
      }
    ]
  }
}
To request the solution, locate the ID from the response to the post operation and append it to the following API call:
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/employee-scheduling/v1/schedules/<ID>
{
  "metadata": {
    "id": "cb7d4ef2-d5d2-4021-8ead-a45a3418df54",
    "originId": "cb7d4ef2-d5d2-4021-8ead-a45a3418df54",
    "name": "Required tag type pairing example",
    "submitDateTime": "2026-05-22T16:20:16.256271+02:00",
    "startDateTime": "2026-05-22T16:20:16.417058+02:00",
    "activeDateTime": "2026-05-22T16:20:16.417547+02:00",
    "completeDateTime": "2026-05-22T16:20:46.430017+02:00",
    "shutdownDateTime": "2026-05-22T16:20:46.430021+02:00",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/960soft",
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Tue A 1",
        "employee": "Ann"
      },
      {
        "id": "Tue A 2",
        "employee": "Beth"
      },
      {
        "id": "Tue B 1",
        "employee": "Carl"
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "metrics": {
          "assignedShifts": 1,
          "durationWorked": "PT8H",
          "durationOfTimePreferencesMet": "PT0S"
        }
      },
      {
        "id": "Beth",
        "metrics": {
          "assignedShifts": 1,
          "durationWorked": "PT8H"
        }
      },
      {
        "id": "Carl",
        "metrics": {
          "assignedShifts": 1,
          "durationWorked": "PT8H"
        }
      }
    ],
    "generatedShifts": []
  },
  "inputMetrics": {
    "employees": 3,
    "shifts": 3,
    "pinnedShifts": 0,
    "mandatoryShifts": 3,
    "optionalShifts": 0
  },
  "kpis": {
    "assignedShifts": 3,
    "unassignedShifts": 0,
    "disruptionPercentage": 0,
    "averageDurationOfEmployeesPreferencesMet": "PT0S",
    "minimumDurationOfPreferencesMetAcrossEmployees": "PT0S",
    "activatedEmployees": 3,
    "assignedMandatoryShifts": 3
  },
  "run": {
    "id": "cb7d4ef2-d5d2-4021-8ead-a45a3418df54",
    "originId": "cb7d4ef2-d5d2-4021-8ead-a45a3418df54",
    "name": "Required tag type pairing example",
    "submitDateTime": "2026-05-22T16:20:16.256271+02:00",
    "startDateTime": "2026-05-22T16:20:16.417058+02:00",
    "activeDateTime": "2026-05-22T16:20:16.417547+02:00",
    "completeDateTime": "2026-05-22T16:20:46.430017+02:00",
    "shutdownDateTime": "2026-05-22T16:20:46.430021+02:00",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/960soft",
    "validationResult": {
      "summary": "OK"
    }
  }
}

modelOutput contains the employee shift schedule with Ann and Beth both assigned to Zone A shifts and Carl assigned to the Zone B shift.

Limiting how many different shift hours a group can work per day

groupShiftsPerDayMax is a preview feature subject to change.

Use groupShiftsPerDayMax together with commonTagType on an employee group, to cap how many different shift hours the group’s members may work on the same day.

A common example is a fixed crew, such as a car pool or a work team, that should mostly cover a single shift together but may occasionally split into a small, limited number of sub-shifts. Setting groupShiftsPerDayMax: 1 reproduces the strictest case: the crew must work identical shift hours on any day they work together and can never be split into multiple shifts. Higher values, like groupShiftsPerDayMax: 2, allow the crew to legitimately split into at most that many different shift hours on the same day.

groupShiftsPerDayMax requires commonTagType to also be set on the employee group. When set, group members who work a shift with the same commonTagType tag on the same day may not work more than groupShiftsPerDayMax different shift hours that day.

{
  "tagTypes": [
    { "id": "Zone A" }
  ],
  "tags": [
    { "id": "Location 1", "tagType": "Zone A" }
  ],
  "employees": [
    { "id": "Ann" },
    { "id": "Beth" }
  ],
  "employeeGroups": [
    {
      "id": "CAR 1",
      "requiredEmployees": [ "Ann", "Beth" ],
      "commonTagType": "Zone A",
      "groupShiftsPerDayMax": 1
    }
  ]
}

In this example, Ann and Beth are both members of the CAR 1 employee group, which specifies commonTagType: Zone A and groupShiftsPerDayMax: 1. This means Ann and Beth must both work shifts tagged with Location 1 and those shifts must start and end at the same time. Assigning Ann to a morning shift and Beth to an afternoon shift at Location 1 on the same day would exceed the limit, since they’d then have 2 distinct sets of shift hours instead of 1.

With groupShiftsPerDayMax: 2 instead, Ann, Beth, and a third crew member Carl could split into two different shift hours (for example, Ann and Beth on the morning shift, Carl on the afternoon shift) without violating the constraint, but a third different set of shift hours on the same day would exceed the limit.

The Group split into multiple shifts per day hard constraint is invoked when an employee group works more different shift hours on a day, among shifts sharing a common tag of the required tag type, than its configured groupShiftsPerDayMax allows.

Declare tags and tag types in the tagTypes and tags top-level collections so that commonTagType resolves correctly. See Tags and tag types for details.

Next

  • See the full API spec, try the online API, or start a free trial.

  • Learn more about employee shift scheduling from our YouTube playlist.

  • Manage Employee availability and preferences.

  • © 2026 Timefold BV
  • Timefold.ai
  • Documentation
  • Changelog
  • Send feedback
  • Privacy
  • Legal
    • Light mode
    • Dark mode
    • System default