Resource-limited planning
In employee shift scheduling, resource-limited planning occurs when there are not enough employees to assign to all the shifts that need to be covered.
When resource-limited planning occurs, you can set shift priorities to control which shifts should be scheduled first.
This guide explains how to manage resource-limited planning with the following examples:
1. Resource-limited planning with no shift priorities
In the following example, there are three shifts that need to be staffed, but only two employees who can cover the shifts.
One of the shifts will be 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": "Resource-limited planning - no priorities"
}
},
"modelInput": {
"employees": [
{
"id": "Ann"
},
{
"id": "Beth"
}
],
"shifts": [
{
"id": "Monday Cashier",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Monday Greeter",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Monday Stockroom",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17: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",
"name": "Resource-limited planning - no priorities",
"submitDateTime": "2025-01-13T06:56:41.254037504Z",
"startDateTime": "2025-01-13T06:56:51.713981203Z",
"activeDateTime": "2025-01-13T06:56:51.776161178Z",
"completeDateTime": "2025-01-13T07:01:51.934602715Z",
"shutdownDateTime": "2025-01-13T07:01:52.199287953Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-1medium/0soft",
"tags": [],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Monday Cashier",
"employee": "Ann"
},
{
"id": "Monday Greeter",
"employee": "Beth"
},
{
"id": "Monday Stockroom",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 2,
"unassignedShifts": 1,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null
}
}
modelOutput
contains Ann’s and Beth’s assigned shifts.
2. Resource-limited planning with shift priorities
In the previous example, only two of three shifts were assigned employees.
-
Ann was assigned the shift
Monday Cashier
. -
Beth was assigned the shift
Monday Greeter
. -
The shift
Monday Stockroom
was left unassigned.
To control which shifts are assigned first, you can add priorities to shifts. There are ten built-in priorities. 1 is the highest priority and 10 is the lowest priority.
Priorities are added to shifts:
{
"shifts": [
{
"id": "Monday Cashier",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "1"
},
{
"id": "Monday Greeter",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "5"
},
{
"id": "Monday Stockroom",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "3"
}
]
}
In the following example, a delivery is due on Monday and a staff member must be present to accept the delivery and store the items. The monday shifts have the following priorities:
-
Cashier: Priority 1
-
Stockroom: Priority 3
-
Greeter: Priority 5
-
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": "Resource-limited planning - with priorities"
}
},
"modelInput": {
"employees": [
{
"id": "Ann"
},
{
"id": "Beth"
}
],
"shifts": [
{
"id": "Monday Cashier",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "1"
},
{
"id": "Monday Greeter",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "5"
},
{
"id": "Monday Stockroom",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "3"
}
]
}
}
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",
"name": "Resource-limited planning - with priorities",
"submitDateTime": "2025-01-13T07:43:38.942914528Z",
"startDateTime": "2025-01-13T07:43:45.837804099Z",
"activeDateTime": "2025-01-13T07:43:45.927185678Z",
"completeDateTime": "2025-01-13T07:48:46.126452389Z",
"shutdownDateTime": "2025-01-13T07:48:46.291891316Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-100000medium/0soft",
"tags": [],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Monday Cashier",
"employee": "Ann"
},
{
"id": "Monday Greeter",
"employee": null
},
{
"id": "Monday Stockroom",
"employee": "Beth"
}
]
},
"kpis": {
"assignedShifts": 2,
"unassignedShifts": 1,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null
}
}
modelOutput
contains Ann’s and Beth’s assigned shifts.
This time, the Monday Greeter
shift has been left unassigned as it has the lowest priority.
3. Mandatory and optional shifts
Shifts can be mandatory or optional.
Unassigned mandatory shifts break a medium constraint and effect the medium score of the solution.
Unassigned optional shifts break a soft constraint and affect the soft score of the solution.
Shifts are mandatory by default.
Making a shift optional means the shift can be left unassigned if this leads to a higher overall score. Scenarios where other soft constraints might be satisfied instead of assigning optional shifts include employee preferences and multi-day shift pattern rules.
In the following example, there are three mandatory shifts and three employees. However, two of the employees (Ann and Beth) have preferences not to work at the same time as the third employee (Carl).
See unpreferred pairings for information about employee preferences.
-
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": "Resource-limited planning - with mandatory shifts"
}
},
"modelInput": {
"employees": [
{
"id": "Ann",
"unpreferredPairings": [
{
"pairedEmployee": "Carl"
}
]
},
{
"id": "Beth",
"unpreferredPairings": [
{
"pairedEmployee": "Carl"
}
]
},
{
"id": "Carl"
}
],
"shifts": [
{
"id": "Monday Cashier",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "1"
},
{
"id": "Monday Greeter",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "5"
},
{
"id": "Monday Stockroom",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "3"
}
]
}
}
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",
"name": "Resource-limited planning - with mandatory shifts",
"submitDateTime": "2025-01-13T08:17:10.602715243Z",
"startDateTime": "2025-01-13T08:17:17.257947788Z",
"activeDateTime": "2025-01-13T08:17:17.332768003Z",
"completeDateTime": "2025-01-13T08:22:17.537407491Z",
"shutdownDateTime": "2025-01-13T08:22:17.69476057Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-1920soft",
"tags": [],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Monday Cashier",
"employee": "Ann"
},
{
"id": "Monday Greeter",
"employee": "Beth"
},
{
"id": "Monday Stockroom",
"employee": "Carl"
}
]
},
"kpis": {
"assignedShifts": 3,
"unassignedShifts": 0,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": "PT5H20M",
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": "PT8H"
}
}
modelOutput
contains Ann’s, Beth’s, and Carl’s assigned shifts.
In this example, Carl is assigned a shift with Ann and Beth.
However, if one of the three shifts was marked as optional, Ann and Beth would be assigned the two mandatory shifts, and the optional shift would be left unassigned.
To define mandatory and optional shifts, create a globalRules
object and an unassignShiftRule
which defines the weight and assignment for each priority level.
{
"globalRules": {
"unassignedShiftRule": {
"id": "unassignedShiftRule",
"priorityWeights": [
{
"priority": "1",
"weight": 100,
"assignment": "MANDATORY"
},
{
"priority": "3",
"weight": 10,
"assignment": "MANDATORY"
},
{
"priority": "5",
"weight": 1,
"assignment": "OPTIONAL"
}
]
}
}
}
In the following example, priority 1 is the highest priority with the greatest weight, and priority 5 is the lowest priority with a weight of 1.
Any shift with a priority level of 1 or 3 are mandatory shifts. Any shift with a priority level of 5 is an optional shift.
Now with two mandatory shifts and one optional shift, the optional shift will be left unassigned in favor of satisfying Ann’s and Beth’s preferences not to work at the same time as Carl.
-
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": "Resource-limited planning - with optional shifts"
}
},
"modelInput": {
"globalRules": {
"unassignedShiftRule": {
"id": "unassignedShiftRule",
"priorityWeights": [
{
"priority": "1",
"weight": 100,
"assignment": "MANDATORY"
},
{
"priority": "3",
"weight": 10,
"assignment": "MANDATORY"
},
{
"priority": "5",
"weight": 1,
"assignment": "OPTIONAL"
}
]
}
},
"employees": [
{
"id": "Ann",
"unpreferredPairings": [
{
"pairedEmployee": "Carl"
}
]
},
{
"id": "Beth",
"unpreferredPairings": [
{
"pairedEmployee": "Carl"
}
]
},
{
"id": "Carl"
}
],
"shifts": [
{
"id": "Monday Cashier",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "1"
},
{
"id": "Monday Greeter",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "5"
},
{
"id": "Monday Stockroom",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"priority": "3"
}
]
}
}
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",
"name": "Resource-limited planning - with optional shifts",
"submitDateTime": "2025-01-13T08:30:18.984846197Z",
"startDateTime": "2025-01-13T08:30:25.717208027Z",
"activeDateTime": "2025-01-13T08:30:25.82002715Z",
"completeDateTime": "2025-01-13T08:35:26.026473606Z",
"shutdownDateTime": "2025-01-13T08:35:26.184985497Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-1soft",
"tags": [],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Monday Cashier",
"employee": "Beth"
},
{
"id": "Monday Greeter",
"employee": null
},
{
"id": "Monday Stockroom",
"employee": "Ann"
}
]
},
"kpis": {
"assignedShifts": 2,
"unassignedShifts": 1,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": "PT0S",
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": "PT0S"
}
}
modelOutput
contains Ann’s and Beth’s assigned shifts.
Next
-
Understand the constraints of the Employee Shift Scheduling model.
-
See the full API spec or try the online API.
-
Manage schedules with Timezones and Daylight Saving Time (DST) changes.
-
Manage Employee availability.