Employee contracts
Employee contracts stipulate the conditions under which the employees work, such as their working hours, the number of hours worked per month, week, or day, and the amount of time that must occur between scheduled shifts.
Contracts can specify shifts to avoid assigning directly before or after the employee has a day off request.
Different groups of employees have different contracts, for instance, full-time employees may expect to work no more than 5 eight-hour shifts per week, while part-time employees might work 3 shifts per week.
Employees have an expectation that the terms of their contracts are honored in the shifts they are scheduled to work. For any employee shift scheduling solution to be feasible, it must take into account the contractual obligations between the employer and the employee.
This guide explains how to manage employee contracts with the following examples:
Prerequisites
To run the examples in this guide, you need to authenticate with a valid API key:
-
Log in to Timefold Platform: app.timefold.ai
-
From the Dashboard, click your username, and from the drop-down menu select API Keys.
-
Copy the default API key.
In the examples, replace <API_KEY>
with the API Key you just copied.
The times displayed in the visualizations are approximates only. |
1. Defining a contract
Contracts include rules that must be applied to groups of employees. For instance:
-
Full-time employees work no more than 5 consecutive days.
-
Part-time employees work no more than 3 consecutive days.
-
Full-time and part-time employees work a maximum of 8 hours a day.
-
Full-time employees work a maximum of 40 hours per week.
-
Part-time employees work a maximum of 24 hours per week.
-
Full-time and part-time employees have at least 12 hours between shifts.
Contracts are defined in the modelInput.
{
"modelInput": {
"contracts": [
{
"id": "fullTimeContract"
},
{
"id": "partTimeContract"
}
]
}
}
Contracts
at a minimum need to include an id
that identifies the contract.
You can define as many contracts as required.
Individual employees reference the contracts that apply to them.
For instance, Ann is a full-time employee and includes fullTimeContract
.
{
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
]
}
]
}
2. Period rules
Period rules stipulate how many hours employees can work in a given period. For instance, a full-time employee might work a maximum of 8 hours per day and a maximum of 40 hours per week.
In the following example, Ann is a full-time employee who works 8 hours per day and 40 hours per week.
Period rules are defined in contracts
.
Multiple periodRules
can be defined.
{
"contracts": [
{
"id": "fullTimeContract",
"periodRules": [
{
"id": "Max8HoursPerDayFullTime",
"period": "DAY",
"minutesWorkedMax": 480
},
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400
}
]
}
]
}
A periodRule
needs to include an id
for the rule, a period
(ie, DAY
, WEEK
, MONTH
, or SCHEDULE
).
In this case, the Max8HoursPerDayFullTime
rule specifies minutesWorkedMax
is 480
or 8 hours for each DAY
period.
Max40HoursPerWeekFullTime
specifies the minutesWorkedMax
is 2400
or 40 hours for each WEEK
period.
It is necessary to specify rules that apply to both the day and the week. If a rule for the week is included that sets a maximum number of hours per week at 40, but no rule is included for the day period, an employee could be assigned continuous shifts for 40 hours and then nothing for the rest of the week. Similarly, if a rule is included that sets a maximum number of hours per day at 8, but no rule is included for the week, an employee could be assigned an eight-hour shift every single day with no days off. |
When there are not enough employees to cover all the shifts, some shifts will be left unassigned.
Leaving shifts unassigned breaks medium constraints but creates a feasible schedule; however, assigning employees more hours than they are contracted to work will break hard constraints and is not a feasible schedule.
Learn about the hard, medium, and soft constraints in Employee Shift Scheduling model. |
-
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": "Contract period rules example"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"periodRules": [
{
"id": "Max8HoursPerDayFullTime",
"period": "DAY",
"minutesWorkedMax": 480
},
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon night",
"start": "2027-02-01T01:00:00Z",
"end": "2027-02-01T09:00:00Z"
},
{
"id": "Mon day",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Tue night",
"start": "2027-02-02T01:00:00Z",
"end": "2027-02-02T09:00:00Z"
},
{
"id": "Tue day",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Wed night",
"start": "2027-02-03T01:00:00Z",
"end": "2027-02-03T09:00:00Z"
},
{
"id": "Wed day",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Thu night",
"start": "2027-02-04T01:00:00Z",
"end": "2027-02-04T09:00:00Z"
},
{
"id": "Thu day",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z"
},
{
"id": "Fri night",
"start": "2027-02-05T01:00:00Z",
"end": "2027-02-05T09:00:00Z"
},
{
"id": "Fri day",
"start": "2027-02-05T09:00:00Z",
"end": "2027-02-05T17:00:00Z"
},
{
"id": "Sat night",
"start": "2027-02-06T01:00:00Z",
"end": "2027-02-06T09:00:00Z"
},
{
"id": "Sat day",
"start": "2027-02-06T09:00:00Z",
"end": "2027-02-06T17: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": "Contract period rules example",
"submitDateTime": "2024-10-21T09:27:52.885391038Z",
"startDateTime": "2024-10-21T09:28:02.300826712Z",
"completeDateTime": "2024-10-21T09:33:02.48500359Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-7medium/0soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon night",
"employee": "Ann"
},
{
"id": "Mon day",
"employee": null
},
{
"id": "Tue night",
"employee": "Ann"
},
{
"id": "Tue day",
"employee": null
},
{
"id": "Wed night",
"employee": "Ann"
},
{
"id": "Wed day",
"employee": null
},
{
"id": "Thu night",
"employee": "Ann"
},
{
"id": "Thu day",
"employee": null
},
{
"id": "Fri night",
"employee": "Ann"
},
{
"id": "Fri day",
"employee": null
},
{
"id": "Sat night",
"employee": null
},
{
"id": "Sat day",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 5,
"unassignedShifts": 7,
"workingTimeFairnessPercentage": 0.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee schedule.
Ann has been assigned 5 shifts with 8 hours per day with a total of 40 hours for the week.
Some shifts have been unassigned.
Shift times use ISO 8601 date time with offset to UTC format. |
2.1. Filtering period rules with tags
Tags can be added to periodRules
and shifts
to control which shifts the period rules apply to.
For instance, if the maximum number of hours per week doesn’t apply to a specific department, the department can be excluded from the rule by adding excludeShiftTags
to the rule and referencing the tag that identifies the department’s shifts:
{
"periodRules": [
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400,
"excludeShiftTags": [
"department A"
],
"shiftTagMatches": "ALL"
}
],
"shifts": [
{
"id": "Mon night",
"start": "2027-02-01T00:00:00Z",
"end": "2027-02-01T08:00:00Z",
"tags": [
"department A"
]
}
]
}
Alternatively, if the rule only applies to a specific department, you can add includeShiftTags
to apply the rule to shifts with the tag.
includeShiftTags and excludeShiftTags can both be used in the same dataset, however, they cannot be used in combination for the same rule.
|
If shifts have multiple tags, you decide whether to match ALL of the tags or ANY of the tags based on the period rule by including shiftTagMatches
and setting it to ALL
or ANY
.
In the following example, department A is understaffed and has decided to let employees work more than the normal 40 hours per week, however, they don’t want employees to work more than eight hours per day.
Department A is excluded from the max40HoursPerWeekFullTime
rule, and Ann is assigned 6 eight-hour shifts for a total of 48 hours in the week.
-
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": "Contract period rules example with tags"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"periodRules": [
{
"id": "Max8HoursPerDayFullTime",
"period": "DAY",
"minutesWorkedMax": 480
},
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400,
"excludeShiftTags":
[
"department A"
],
"shiftTagMatches": "ALL"
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon night",
"start": "2027-02-01T01:00:00Z",
"end": "2027-02-01T09:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Mon day",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Tue night",
"start": "2027-02-02T01:00:00Z",
"end": "2027-02-02T09:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Tue day",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Wed night",
"start": "2027-02-03T01:00:00Z",
"end": "2027-02-03T09:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Wed day",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Thu night",
"start": "2027-02-04T01:00:00Z",
"end": "2027-02-04T09:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Thu day",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Fri night",
"start": "2027-02-05T01:00:00Z",
"end": "2027-02-05T09:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Fri day",
"start": "2027-02-05T09:00:00Z",
"end": "2027-02-05T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Sat night",
"start": "2027-02-06T01:00:00Z",
"end": "2027-02-06T09:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Sat day",
"start": "2027-02-06T09:00:00Z",
"end": "2027-02-06T17:00:00Z",
"tags": [
"department A"
]
}
]
}
}
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": "Contract period rules example with tags",
"submitDateTime": "2024-10-21T09:34:38.882106303Z",
"startDateTime": "2024-10-21T09:34:43.750759794Z",
"completeDateTime": "2024-10-21T09:39:43.977385095Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-6medium/0soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon night",
"employee": "Ann"
},
{
"id": "Mon day",
"employee": null
},
{
"id": "Tue night",
"employee": "Ann"
},
{
"id": "Tue day",
"employee": null
},
{
"id": "Wed night",
"employee": "Ann"
},
{
"id": "Wed day",
"employee": null
},
{
"id": "Thu night",
"employee": "Ann"
},
{
"id": "Thu day",
"employee": null
},
{
"id": "Fri night",
"employee": "Ann"
},
{
"id": "Fri day",
"employee": null
},
{
"id": "Sat night",
"employee": "Ann"
},
{
"id": "Sat day",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 6,
"unassignedShifts": 6,
"workingTimeFairnessPercentage": 0.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee schedule with Ann scheduled to work 6 eight-hour days for a total of 48 hours that week.
3. Consecutive days worked rule
Contracts can include rules about the maximum or minimum number of consecutive days employees work.
In the following example, Beth works 3 consecutive twelve-hour shifts.
Consecutive day worked rules are defined in contracts
.
{
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3
}
]
}
]
}
A consecutiveDaysWorkedRules
needs to include an id
for the rule, and a maximum
or minimum
number of days that can be worked consecutively.
In this instance, the rule states a maximum of 3 consecutive days can be worked.
The maximum and minimum can be combined, for instance, a minimum of 2 consecutive days and 3 maximum consecutive days. Such a rule would result in an employee being assigned between 2 and 3 days inclusive in the shift schedule.
In the following example, Beth works 3 consecutive twelve-hour shifts.
-
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": "Consecutive days worked rule example"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3
}
]
}
],
"employees": [
{
"id": "Beth",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon",
"start": "2027-02-01T08:00:00Z",
"end": "2027-02-01T20:00:00Z"
},
{
"id": "Tue",
"start": "2027-02-02T08:00:00Z",
"end": "2027-02-02T20:00:00Z"
},
{
"id": "Wed",
"start": "2027-02-03T08:00:00Z",
"end": "2027-02-03T20:00:00Z"
},
{
"id": "Thu",
"start": "2027-02-04T08:00:00Z",
"end": "2027-02-04T20: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": "Consecutive days worked rule example",
"submitDateTime": "2024-10-21T09:41:26.684484561Z",
"startDateTime": "2024-10-21T09:41:31.446186159Z",
"completeDateTime": "2024-10-21T09:46:31.654904532Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-1medium/0soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon",
"employee": "Beth"
},
{
"id": "Tue",
"employee": "Beth"
},
{
"id": "Wed",
"employee": "Beth"
},
{
"id": "Thu",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 3,
"unassignedShifts": 1,
"workingTimeFairnessPercentage": 0.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee schedule with Beth assigned three consecutive shifts.
Consecutive days worked rules applies to the number of consecutive days worked, not the number of days worked over a specific period. To limit the number of days over a specific period (for instance a week), include a period rule. See Combining contract rules example for an example of including multiple contract rules. |
3.1. Filtering consecutive days worked with tags
Tags can be added to consecutiveDaysWorkedRule
and shifts
to control which shifts the consecutive days worked rules apply to.
For instance, if an employee works a five-day week, but is only allowed to work 2 consecutive days in a specific department, you can define a consecutive days worked rule of 2 days for that department.
Add includeShiftTags
to the rule and reference the tag that identifies the department’s shifts.
{
"consecutiveDaysWorkedRules": [
{
"id": "Max2ConsecutiveDaysDepartmentA",
"maximum": 2,
"includeShiftTags": [
"department A"
],
"shiftTagMatches": "ALL"
}
],
"shifts": [
{
"id": "Mon night",
"start": "2027-02-01T00:00:00Z",
"end": "2027-02-01T08:00:00Z",
"tags": [
"department A"
]
}
]
}
In the following example, Ann is a full time employee who works five days per week, but can only work two consecutive days in department A. She is assigned to Monday and Tuesday in department A, Wednesday in department B, and Thursday and Friday in department A again.
-
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": "Consecutive days worked rule example with tags"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max2ConsecutiveDaysDepartmentA",
"maximum": 2,
"includeShiftTags":
[
"department A"
],
"shiftTagMatches": "ALL"
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon department A",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Tue department A",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Wed department A",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Wed department B",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z",
"tags": [
"department B"
]
},
{
"id": "Thu department A",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z",
"tags": [
"department A"
]
},
{
"id": "Fri department A",
"start": "2027-02-05T09:00:00Z",
"end": "2027-02-05T17:00:00Z",
"tags": [
"department A"
]
}
]
}
}
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": "Consecutive days worked rule example with tags",
"submitDateTime": "2024-10-21T09:49:11.055051606Z",
"startDateTime": "2024-10-21T09:49:15.855077369Z",
"completeDateTime": "2024-10-21T09:54:16.060270963Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-1medium/0soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon department A",
"employee": "Ann"
},
{
"id": "Tue department A",
"employee": "Ann"
},
{
"id": "Wed department A",
"employee": null
},
{
"id": "Wed department B",
"employee": "Ann"
},
{
"id": "Thu department A",
"employee": "Ann"
},
{
"id": "Fri department A",
"employee": "Ann"
}
]
},
"kpis": {
"assignedShifts": 5,
"unassignedShifts": 1,
"workingTimeFairnessPercentage": 0.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee schedule with Ann assigned to Monday and Tuesday in department A, Wednesday in department B, and Thursday and Friday in department A again.
4. Minutes between shifts rules
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 the following day shift.
You can specify the minimum or maximum time between shifts with minutesBetweenShiftRules
in contracts
.
Additionally, you can provide a scope for the rule.
The scope will limit which pairs of shifts the rule is applied to.
The scope excludes shift pairs where the start of the later shift is after the end of the prior shift plus the scope duration.
{
"contracts": [
{
"id": "fullTimeContract",
"minutesBetweenShiftsRules": [
{
"id": "Minimum12HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"scope": {
"type": "duration",
"duration": "P1D"
}
}
]
}
]
}
The minimum time between shifts is defined in contracts
.
minutesBetweenShiftsRules
needs to include an id
for the rule and the time between shifts in minutes.
In this instance, the time between shifts is 720
minutes, which ensures employees have 12 hours between assigned shifts.
If Carl works the night shift between 01:00 and 09:00, he will not be eligible for another shift until 12 hours later at or after 21:00.
-
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": "Contract shift minutes between shifts example",
"tags": []
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"minutesBetweenShiftsRules": [
{
"id": "Minimum12HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720,
"maximumMinutesBetweenShifts": 1440,
"scope": {
"type": "duration",
"duration": "P1D"
}
}
]
}
],
"employees": [
{
"id": "Carl",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon night",
"start": "2027-02-01T01:00:00Z",
"end": "2027-02-01T09:00:00Z"
},
{
"id": "Mon day",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Tue night",
"start": "2027-02-02T01:00:00Z",
"end": "2027-02-02T09:00:00Z"
},
{
"id": "Tue day",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Wed night",
"start": "2027-02-03T01:00:00Z",
"end": "2027-02-03T09:00:00Z"
},
{
"id": "Wed day",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Thu night",
"start": "2027-02-04T01:00:00Z",
"end": "2027-02-04T09:00:00Z"
},
{
"id": "Thu day",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z"
},
{
"id": "Fri night",
"start": "2027-02-05T01:00:00Z",
"end": "2027-02-05T09:00:00Z"
},
{
"id": "Fri day",
"start": "2027-02-05T09:00:00Z",
"end": "2027-02-05T17: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": "Contract shift minutes between shifts example",
"submitDateTime": "2024-10-21T09:55:47.978869443Z",
"startDateTime": "2024-10-21T09:55:52.675396602Z",
"completeDateTime": "2024-10-21T10:00:52.874551078Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-5medium/0soft",
"tags": [],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon night",
"employee": "Carl"
},
{
"id": "Mon day",
"employee": null
},
{
"id": "Tue night",
"employee": "Carl"
},
{
"id": "Tue day",
"employee": null
},
{
"id": "Wed night",
"employee": "Carl"
},
{
"id": "Wed day",
"employee": null
},
{
"id": "Thu night",
"employee": "Carl"
},
{
"id": "Thu day",
"employee": null
},
{
"id": "Fri night",
"employee": "Carl"
},
{
"id": "Fri day",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 5,
"unassignedShifts": 5,
"workingTimeFairnessPercentage": 0.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee schedule with Carl assigned shifts with more than 12 hours between each shift.
5. Combining contract rules example
Contract rules provide the most control over the schedules when they are used in combination with each other.
For instance, in the consecutive days worked rule example, Beth worked 3 consecutive twelve-hour shifts. If we don’t also define a period rule for the number of hours per week, Beth could be assigned a twelve-hour shift on Monday, Tuesday, and Wednesday, have no shift assigned on Thursday, and then be assign three more consecutive shifts on Friday, Saturday, and Sunday. If the intention is for Beth to work 3 consecutive shifts per week, we also need to include a period rule to prevent more shifts being assigned after those three days and the following day.
The following example defines a contract with the following rules:
-
Employees work a maximum of 8 hours per day.
-
Employees work a maximum of 40 hours per week.
-
Employees work a maximum of 5 consecutive days.
-
Employees have 12 hours between shifts.
-
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": "Contract shift times example",
"tags": []
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max5ConsecutiveDaysFullTime",
"maximum": 5
}
],
"periodRules": [
{
"id": "Max8HoursPerDayFullTime",
"period": "DAY",
"minutesWorkedMax": 480
},
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400
}
],
"minutesBetweenShiftsRules": [
{
"id": "Minimum12HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon night",
"start": "2027-02-01T01:00:00Z",
"end": "2027-02-01T09:00:00Z"
},
{
"id": "Mon day",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Tue night",
"start": "2027-02-02T01:00:00Z",
"end": "2027-02-02T09:00:00Z"
},
{
"id": "Tue day",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Wed night",
"start": "2027-02-03T01:00:00Z",
"end": "2027-02-03T09:00:00Z"
},
{
"id": "Wed day",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Thu night",
"start": "2027-02-04T01:00:00Z",
"end": "2027-02-04T09:00:00Z"
},
{
"id": "Thu day",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z"
},
{
"id": "Fri night",
"start": "2027-02-05T01:00:00Z",
"end": "2027-02-05T09:00:00Z"
},
{
"id": "Fri day",
"start": "2027-02-05T09:00:00Z",
"end": "2027-02-05T17:00:00Z"
},
{
"id": "Sat night",
"start": "2027-02-06T01:00:00Z",
"end": "2027-02-06T09:00:00Z"
},
{
"id": "Sat day",
"start": "2027-02-06T09:00:00Z",
"end": "2027-02-06T17: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": "Contract shift times example",
"submitDateTime": "2024-10-21T10:05:02.930407315Z",
"startDateTime": "2024-10-21T10:05:07.964859924Z",
"completeDateTime": "2024-10-21T10:10:08.215530452Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-7medium/0soft",
"tags": [],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon night",
"employee": "Ann"
},
{
"id": "Mon day",
"employee": null
},
{
"id": "Tue night",
"employee": "Ann"
},
{
"id": "Tue day",
"employee": null
},
{
"id": "Wed night",
"employee": "Ann"
},
{
"id": "Wed day",
"employee": null
},
{
"id": "Thu night",
"employee": "Ann"
},
{
"id": "Thu day",
"employee": null
},
{
"id": "Fri night",
"employee": "Ann"
},
{
"id": "Fri day",
"employee": null
},
{
"id": "Sat night",
"employee": null
},
{
"id": "Sat day",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 5,
"unassignedShifts": 7,
"workingTimeFairnessPercentage": 0.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee schedule which conforms with the contract rules in the modelInput.
6. Avoid shift close to day off request rules
When Employees have days off, there are shifts it would be better not to assign them before or after the day off.
Days off are defined by employee availability. See Employee availability for details. |
Assigning an afternoon shift to an employee directly before a day off might make it difficult for the employee to use their day off as they intended. Similarly, employees might prefer not to have an early shift after a day off.
{
"contracts": [
{
"id": "fullTimeContract",
"avoidShiftCloseToDayOffRequestRules": [
{
"id": "noNightAndMorningShiftsNearDayOff",
"avoidPriorShiftTags": [ "afternoon" ],
"avoidAfterShiftTags": [ "morning" ],
"shiftTagMatches": "ANY",
"satisfiability": "PROHIBITED"
}
]
}
]
}
avoidShiftCloseToDayOffRequestRules
is defined in contracts
and must include an id
for the rule.
-
avoidPriorShiftTags
must include the tags for the shifts to excluded prior to a day off request, for instance,afternoon
. If no tags are provided, the rule has no effect on shifts the day prior to a day off request. -
avoidAfterShiftTags
must include the tags for the shifts to exclude after a day off request, for instance,morning
. If no tags are provided, the rule has no effect on shifts the day after a day off request.
In the following example, Ann can work morning, afternoon, or night shifts.
She has Wednesday off as defined by the employee unavailabletimeSpan
.
The unavailable timespan starts at 00:00 on Wednesday and ends at 00:00 on Thursday, and she cannot be assigned to any shifts that overlap this time period.
The avoidShiftCloseToDayOffRequestRules
prohibits Ann from working an afternoon shift the day before her day off and from working a morning shift the day after her day off.
-
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": "Avoid shifts close to days off example"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max5ConsecutiveDaysFullTime",
"maximum": 5
}
],
"periodRules": [
{
"id": "Max8HoursPerDayFullTime",
"period": "DAY",
"minutesWorkedMax": 480
},
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400
}
],
"minutesBetweenShiftsRules": [
{
"id": "Minimum12HoursBetweenShiftsFullTime",
"minimumMinutesBetweenShifts": 720
}
],
"avoidShiftCloseToDayOffRequestRules": [
{
"id": "noMorningShiftsNearDayOff",
"avoidPriorShiftTags": [
"afternoon"
],
"avoidAfterShiftTags": [
"morning"
],
"shiftTagMatches": "ANY",
"satisfiability": "PROHIBITED"
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
],
"unavailableTimeSpans": [
{
"start": "2027-02-03T00:00:00-04:00",
"end": "2027-02-04T00:00:00-04:00"
}
]
}
],
"shifts": [
{
"id": "Mon morning",
"start": "2027-02-01T06:00:00-04:00",
"end": "2027-02-01T14:00:00-04:00",
"tags": [
"morning"
]
},
{
"id": "Mon afternoon",
"start": "2027-02-01T14:00:00-04:00",
"end": "2027-02-01T22:00:00-04:00",
"tags": [
"afternoon"
]
},
{
"id": "Mon night",
"start": "2027-02-01T22:00:00-04:00",
"end": "2027-02-02T06:00:00-04:00",
"tags": [
"night"
]
},
{
"id": "Tue morning",
"start": "2027-02-02T06:00:00-04:00",
"end": "2027-02-02T14:00:00-04:00",
"tags": [
"morning"
]
},
{
"id": "Tue afternoon",
"start": "2027-02-02T14:00:00-04:00",
"end": "2027-02-02T22:00:00-04:00",
"tags": [
"afternoon"
]
},
{
"id": "Tue night",
"start": "2027-02-02T22:00:00-04:00",
"end": "2027-02-03T06:00:00-04:00",
"tags": [
"night"
]
},
{
"id": "Wed morning",
"start": "2027-02-03T06:00:00-04:00",
"end": "2027-02-03T14:00:00-04:00",
"tags": [
"morning"
]
},
{
"id": "Wed afternoon",
"start": "2027-02-03T14:00:00-04:00",
"end": "2027-02-03T22:00:00-04:00",
"tags": [
"afternoon"
]
},
{
"id": "Wed night",
"start": "2027-02-03T22:00:00-04:00",
"end": "2027-02-04T06:00:00-04:00",
"tags": [
"night"
]
},
{
"id": "Thu morning",
"start": "2027-02-04T06:00:00-04:00",
"end": "2027-02-04T14:00:00-04:00",
"tags": [
"morning"
]
},
{
"id": "Thu afternoon",
"start": "2027-02-04T14:00:00-04:00",
"end": "2027-02-04T22:00:00-04:00",
"tags": [
"afternoon"
]
},
{
"id": "Thu night",
"start": "2027-02-04T22:00:00-04:00",
"end": "2027-02-05T06:00:00-04:00",
"tags": [
"night"
]
},
{
"id": "Fri morning",
"start": "2027-02-05T06:00:00-04:00",
"end": "2027-02-05T14:00:00-04:00",
"tags": [
"morning"
]
},
{
"id": "Fri afternoon",
"start": "2027-02-05T14:00:00-04:00",
"end": "2027-02-05T22:00:00-04:00",
"tags": [
"afternoon"
]
},
{
"id": "Fri night",
"start": "2027-02-05T22:00:00-04:00",
"end": "2027-02-06T06:00:00-04:00",
"tags": [
"night"
]
},
{
"id": "Sat morning",
"start": "2027-02-06T06:00:00-04:00",
"end": "2027-02-06T14:00:00-04:00",
"tags": [
"morning"
]
},
{
"id": "Sat afternoon",
"start": "2027-02-06T14:00:00-04:00",
"end": "2027-02-06T22:00:00-04:00",
"tags": [
"afternoon"
]
},
{
"id": "Sat night",
"start": "2027-02-06T22:00:00-04:00",
"end": "2027-02-07T06:00:00-04:00",
"tags": [
"night"
]
}
]
}
}
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": "Avoid shifts close to days off example",
"submitDateTime": "2024-10-22T00:53:42.978851235Z",
"startDateTime": "2024-10-22T00:53:47.475829006Z",
"completeDateTime": "2024-10-22T00:58:47.65514026Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-13medium/0soft",
"tags": null,
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon morning",
"employee": "Ann"
},
{
"id": "Mon afternoon",
"employee": null
},
{
"id": "Mon night",
"employee": null
},
{
"id": "Tue morning",
"employee": "Ann"
},
{
"id": "Tue afternoon",
"employee": null
},
{
"id": "Tue night",
"employee": null
},
{
"id": "Wed morning",
"employee": null
},
{
"id": "Wed afternoon",
"employee": null
},
{
"id": "Wed night",
"employee": null
},
{
"id": "Thu morning",
"employee": null
},
{
"id": "Thu afternoon",
"employee": "Ann"
},
{
"id": "Thu night",
"employee": null
},
{
"id": "Fri morning",
"employee": null
},
{
"id": "Fri afternoon",
"employee": "Ann"
},
{
"id": "Fri night",
"employee": null
},
{
"id": "Sat morning",
"employee": null
},
{
"id": "Sat afternoon",
"employee": "Ann"
},
{
"id": "Sat night",
"employee": null
}
]
},
"kpis": {
"assignedShifts": 5,
"unassignedShifts": 13,
"workingTimeFairnessPercentage": 100.0,
"disruptionPercentage": 0.0
}
}
modelOutput
contains the employee shift schedule with Ann enjoying her day off on Wednesday.
She is not assigned an afternoon shift on Tuesday or a morning shift on Thursday.
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.
-
Working with Employee availability.
-
Accommodating Employee preferences.