Minutes between shifts
Employees need time between shifts for their lives outside work.
Contractually, employees could be entitled to a minimum time between shifts, for instance, if an employee works a night shift, it might be included in their contract that they don’t work for the following 12 hours.
Prerequisites
Learn how to configure an API Key to run the examples in this guide:
-
Log in to Timefold Platform: app.timefold.ai
-
From the Dashboard, click your tenant, and from the drop-down menu select Tenant Settings, then choose API Keys.
-
Create a new API key or use an existing one. Ensure the list of models for the API key contains the Employee Shift Scheduling model.
In the examples, replace <API_KEY>
with the API Key you just copied.
1. Define minutes between shifts
minutesBetweenShiftRules
are defined in contracts
.
{
"contracts": [
{
"id": "fullTimeContract",
"minutesBetweenShiftsRules": [
{
"id": "Min12Max24HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"scope": {
"type": "duration",
"duration": "P1D"
},
"satisfiability": "REQUIRED"
}
]
}
]
}
minutesBetweenShiftsRules
must include an id
.
In this instance, the minimumMinutesBetweenShifts
is 720
minutes, which ensures employees have 12 hours between assigned shifts.
The maximumMinutesBetweenShifts
is 1440
minutes, which means the next shift should be assigned no more than 24 hours later.
scope
limits the shift pairs the rule applies to.
The rule excludes shift pairs where the start of the after shift is after the end of the prior shift plus the duration.
scope
must include type
and duration
.
type
currently only supports duration
.
duration
The duration in ISO 8601 format, for instance, P1D
.
requiredAfterShiftTags
can be optionally set to limit the rule so that it only applies when the tag or tags specified by the requiredAfterShiftTags
are present in the next shift that is assigned to the employee.
In the following example, the rule will only if the next shift assigned to the employee is tagged with "Night".
{
"minutesBetweenShiftsRules": [
{
"id": "Min12Max24HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"requiredAfterShiftTags": ["Night"],
"shiftTagMatches": "ALL",
"scope": {
"type": "duration",
"duration": "P1D"
},
"satisfiability": "REQUIRED"
}
]
}
requiredPriorShiftTags
can be optionally set to limit the rule so that it only applies when the tag or tags specified by the requiredPriorShiftTags
are present in the previous shift assigned to the employee.
{
"minutesBetweenShiftsRules": [
{
"id": "Min12Max24HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"requiredPriorShiftTags": ["Night"],
"shiftTagMatches": "ALL",
"scope": {
"type": "duration",
"duration": "P1D"
},
"satisfiability": "REQUIRED"
}
]
}
In the following example, the rule will only if the previous shift assigned to the employee is tagged with "Night".
shiftTagMatches
can be set to ALL
or ANY
.
When set to ALL
, all tags defined by the rule must be present in the shift.
set to ANY
, at least one tag defined by the rule must be present in the shift.
The default behavior for shiftTagMatches
is ALL
, and if omitted, the default ALL
will be used.
With requiredAfterShiftTags
, you can optionally define a minimumConsecutivePriorShifts
attribute to work with a daily sequence of prior shifts.
minimumConsecutivePriorShifts
can be either 1
or 2
.
When the value is 1, the rule will be invoked after a sequence of 1 prior shift that includes the tags specified in requiredAfterShiftTags
shift assigned to the employee.
When the value is 2, the rule will be invoked after a sequence of 2 prior shifts that include the tags specified in requiredAfterShiftTags
shift assigned to the employee.
The satisfiability
of the rule can be REQUIRED
or PREFERRED
.
If omitted, REQUIRED
is the default.
2. Required minutes between shifts
When the satisfiability of the rule is REQUIRED
, the Minutes between shifts not in required range for employee
hard constraint is invoked, making sure the number of minutes between shifts assigned to an employee is not below the minimumMinutesBetweenShifts
or above the maximumMinutesBetweenShifts
.
Shifts will be left unassigned if assigning the shifts breaks the constraint.
In the following example, Carl works the night shift between 00:00 and 08:00, he will not be eligible for another shift until 12 hours later at or after 20:00. There are 5 night shift and 5 day shifts. Carl is assigned the night shifts and the day shift are left unassigned.

-
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 minutes between shifts example",
"tags": []
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"minutesBetweenShiftsRules": [
{
"id": "Min12Max24HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"scope": {
"type": "duration",
"duration": "P1D"
},
"satisfiability": "REQUIRED"
}
]
}
],
"employees": [
{
"id": "Carl",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon 1",
"start": "2027-02-01T00:00:00Z",
"end": "2027-02-01T08:00:00Z"
},
{
"id": "Mon 2",
"start": "2027-02-01T08:00:00Z",
"end": "2027-02-01T16:00:00Z"
},
{
"id": "Tue 1",
"start": "2027-02-02T00:00:00Z",
"end": "2027-02-02T08:00:00Z"
},
{
"id": "Tue 2",
"start": "2027-02-02T08:00:00Z",
"end": "2027-02-02T16:00:00Z"
},
{
"id": "Wed 1",
"start": "2027-02-03T00:00:00Z",
"end": "2027-02-03T08:00:00Z"
},
{
"id": "Wed 2",
"start": "2027-02-03T08:00:00Z",
"end": "2027-02-03T16:00:00Z"
},
{
"id": "Thu 1",
"start": "2027-02-04T00:00:00Z",
"end": "2027-02-04T08:00:00Z"
},
{
"id": "Thu 2",
"start": "2027-02-04T08:00:00Z",
"end": "2027-02-04T16:00:00Z"
},
{
"id": "Fri 1",
"start": "2027-02-05T00:00:00Z",
"end": "2027-02-05T08:00:00Z"
},
{
"id": "Fri 2",
"start": "2027-02-05T08:00:00Z",
"end": "2027-02-05T16:00:00Z"
}
]
}
}
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>
{
"run": {
"id": "ID",
"parentId": null,
"originId": "ID",
"name": "Required minutes between shifts example",
"submitDateTime": "2025-06-20T03:55:08.805661318Z",
"startDateTime": "2025-06-20T03:55:19.324204216Z",
"activeDateTime": "2025-06-20T03:55:19.494220139Z",
"completeDateTime": "2025-06-20T03:55:50.142101896Z",
"shutdownDateTime": "2025-06-20T03:55:50.397703352Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-5medium/0soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 1",
"employee": "Carl"
},
{
"id": "Mon 2"
},
{
"id": "Tue 1",
"employee": "Carl"
},
{
"id": "Tue 2"
},
{
"id": "Wed 1",
"employee": "Carl"
},
{
"id": "Wed 2"
},
{
"id": "Thu 1",
"employee": "Carl"
},
{
"id": "Thu 2"
},
{
"id": "Fri 1",
"employee": "Carl"
},
{
"id": "Fri 2"
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 10,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 5,
"unassignedShifts": 5,
"disruptionPercentage": 0.0,
"activatedEmployees": 1,
"assignedMandatoryShifts": 5,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput
contains the employee schedule with Carl assigned shifts with more than 12 hours between each shift.
inputMetrics
provides a breakdown of the inputs in the input dataset.
KPIs
provides the KPIs for the output including:
{
"assignedShifts": 3,
"unassignedShifts": 3,
"activatedEmployees": 1,
"assignedMandatoryShifts": 3
}
3. Preferred minutes between shifts
When the satisfiability of the rule is PREFERRED
, the Minutes between shifts not in preferred range for employee
soft constraint is invoked.
Employees might be assigned shifts that are below the minimumMinutesBetweenShifts
or above the maximumMinutesBetweenShifts
, but the constraint adds a soft penalty to the run score for any matches to the constraint, incentivizing Timefold to find an alternative solution.
{
"contracts": [
{
"id": "fullTimeContract",
"minutesBetweenShiftsRules": [
{
"id": "Minimum12HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"scope": {
"type": "duration",
"duration": "P1D"
},
"satisfiability": "PREFERRED"
}
]
}
]
}
In the following example, there are 5 night shift and 5 day shifts. There is a minutes between shifts rules with a preferred satisfiability that states Carl should not be assigned another shift until 720 minutes after his last shift. Carl is assigned all the shifts and a soft penalty is applied to the run score.

-
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": "Preferred minutes between shifts example",
"tags": []
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"minutesBetweenShiftsRules": [
{
"id": "Min12Max24HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"scope": {
"type": "duration",
"duration": "P1D"
},
"satisfiability": "PREFERRED"
}
]
}
],
"employees": [
{
"id": "Carl",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon 1",
"start": "2027-02-01T00:00:00Z",
"end": "2027-02-01T08:00:00Z"
},
{
"id": "Mon 2",
"start": "2027-02-01T08:00:00Z",
"end": "2027-02-01T16:00:00Z"
},
{
"id": "Tue 1",
"start": "2027-02-02T00:00:00Z",
"end": "2027-02-02T08:00:00Z"
},
{
"id": "Tue 2",
"start": "2027-02-02T08:00:00Z",
"end": "2027-02-02T16:00:00Z"
},
{
"id": "Wed 1",
"start": "2027-02-03T00:00:00Z",
"end": "2027-02-03T08:00:00Z"
},
{
"id": "Wed 2",
"start": "2027-02-03T08:00:00Z",
"end": "2027-02-03T16:00:00Z"
},
{
"id": "Thu 1",
"start": "2027-02-04T00:00:00Z",
"end": "2027-02-04T08:00:00Z"
},
{
"id": "Thu 2",
"start": "2027-02-04T08:00:00Z",
"end": "2027-02-04T16:00:00Z"
},
{
"id": "Fri 1",
"start": "2027-02-05T00:00:00Z",
"end": "2027-02-05T08:00:00Z"
},
{
"id": "Fri 2",
"start": "2027-02-05T08:00:00Z",
"end": "2027-02-05T16:00:00Z"
}
]
}
}
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>
{
"run": {
"id": "ID",
"parentId": null,
"originId": "ID",
"name": "Preferred minutes between shifts example",
"submitDateTime": "2025-06-20T04:18:51.093250351Z",
"startDateTime": "2025-06-20T04:19:05.093870302Z",
"activeDateTime": "2025-06-20T04:19:05.227695908Z",
"completeDateTime": "2025-06-20T04:19:36.166447379Z",
"shutdownDateTime": "2025-06-20T04:19:36.464541895Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-9120soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 1",
"employee": "Carl"
},
{
"id": "Mon 2",
"employee": "Carl"
},
{
"id": "Tue 1",
"employee": "Carl"
},
{
"id": "Tue 2",
"employee": "Carl"
},
{
"id": "Wed 1",
"employee": "Carl"
},
{
"id": "Wed 2",
"employee": "Carl"
},
{
"id": "Thu 1",
"employee": "Carl"
},
{
"id": "Thu 2",
"employee": "Carl"
},
{
"id": "Fri 1",
"employee": "Carl"
},
{
"id": "Fri 2",
"employee": "Carl"
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 10,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 10,
"unassignedShifts": 0,
"disruptionPercentage": 0.0,
"activatedEmployees": 1,
"assignedMandatoryShifts": 10,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput
contains the schedule with Carl assigned to all shifts.
inputMetrics
provides a breakdown of the inputs in the input dataset.
KPIs
provides the KPIs for the output including:
{
"assignedShifts": 6,
"activatedEmployees": 1,
"assignedMandatoryShifts": 6
}
Next
-
See the full API spec or try the online API.
-
Learn more about employee shift scheduling from our YouTube playlist.
-
See other options for Shift rotations and patterns.