Employee contracts
Employees have an expectation that the terms of their contracts are honored in the shifts they are scheduled to work.
Employee contracts stipulate the conditions under which the employees work, such as their working hours, the number of hours worked, the amount of time that must occur between scheduled shifts, and how on call shifts are managed.
Contracts can also define travel configurations which define where employees work and how far they can travel to their shifts.
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.
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 contract period rules with the following examples:
For rules related to employees' hours, see Employee contracts: Period rules.
For rules related to when employees work, see Employee contracts: Shift rules.
For rules related to where employees work, see Shift travel and locations.
Prerequisites
To run the examples in this guide, you need to authenticate with a valid API key for the Employee Shift Scheduling model:
-
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. 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.
-
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 with the contract fullTimeContract
.
{
"employees": [
{
"id": "Ann",
"contracts": [
"fullTimeContract"
]
}
]
}
Contracts include different kinds of rules, for instance, periodRules
determine how many hours employees are contracted to work and what kinds of shifts they can be assigned. For instance:
{
"contracts": [
{
"id": "fullTimeContract",
"periodRules": [
{
"id": "Max8HoursPerDayFullTime",
"period": "DAY",
"minutesWorkedMax": 480,
"satisfiability": "REQUIRED",
"periodShiftOverlapKind": "START_AND_END"
},
{
"id": "Max40HoursPerWeekFullTime",
"period": "WEEK",
"minutesWorkedMax": 2400,
"satisfiability": "REQUIRED"
}
]
}
]
}
See Employee contracts: Period rules for more details.
Shift rules determine when employees shifts can occur, including how many consecutive shifts they can work, how much time they have between shifts, and how overlapping shifts (such as on call shifts) are managed:
{
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3,
"satisfiability": "REQUIRED"
}
]
}
]
}
see Employee contracts: Shift rules for more details.
Travel configurations define where employees work and how far they can travel to their shifts:
{
"contracts": [
{
"id": "fullTimeContract",
"travelConfigurations": [
{
"id": "maxTravel25000meters",
"maxEmployeeToShiftTravelDistanceInMeters": 25000
}
]
}
]
}
See Shift travel and locations for more details.
2. Giving contracts priority
There are situations where some contracts might be more flexible than others, for instance, if an employer needs to assign employees more shifts or hours in the form of overtime that goes above what is stated in their contract.
When a contract must be strictly adhered to it includes a satisfiability of REQUIRED
.
When a contract is more flexible it includes a satisfiability of PREFERRED
.
Contracts can be given priorities.
{
"contracts": [
{
"id": "partTimeContractNoOverTime",
"priority": "1",
"periodRules": [
{
"id": "Max24HoursNoOverTime",
"period": "WEEK",
"minutesWorkedMax": 1440,
"satisfiability": "PREFERRED"
}
]
}
]
}
By default, priority 1 is the highest priority, and priority 10 is the lowest priority. A contract with priority 1 has 10 times more impact than an identical contract with priority 10.
The higher a contract’s priority, the more likely the contract will be satisfied.
2.1. Contracts with the default priority
In the following example, there are two employees with a contract that set the employees' hours at a maximum of 24 hours a week.
When overtime is required, either employee could be assigned the overtime.
In this case, Ann is assigned the overtime.

-
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 default priority example"
}
},
"modelInput": {
"contracts": [
{
"id": "partTimeContract",
"periodRules": [
{
"id": "Max24HoursPerWeekPartTime",
"period": "WEEK",
"minutesWorkedMax": 1440,
"satisfiability": "PREFERRED"
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"partTimeContract"
]
},
{
"id": "Beth",
"contracts": [
"partTimeContract"
]
}
],
"shifts": [
{
"id": "Mon 1",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Mon 2",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Tue 1",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Tue 2",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Wed 1",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Wed 2",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Thu 1",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z"
},
{
"id": "Fri 1",
"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 default priority example",
"submitDateTime": "2025-03-25T07:41:55.082356578Z",
"startDateTime": "2025-03-25T07:42:08.707356901Z",
"activeDateTime": "2025-03-25T07:42:08.916836532Z",
"completeDateTime": "2025-03-25T07:47:09.944224926Z",
"shutdownDateTime": "2025-03-25T07:47:10.303911335Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-1920soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 1",
"employee": "Ann"
},
{
"id": "Mon 2",
"employee": "Beth"
},
{
"id": "Tue 1",
"employee": "Ann"
},
{
"id": "Tue 2",
"employee": "Beth"
},
{
"id": "Wed 1",
"employee": "Ann"
},
{
"id": "Wed 2",
"employee": "Beth"
},
{
"id": "Thu 1",
"employee": "Ann"
},
{
"id": "Fri 1",
"employee": "Ann"
}
]
},
"inputMetrics": {
"employees": 2,
"shifts": 8,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 8,
"unassignedShifts": 0,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
"activatedEmployees": 2,
"assignedMandatoryShifts": 8,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput
contains the schedule with Ann assigned the overtime shifts.
inputMetrics
provides a breakdown of the inputs in the input dataset.
KPIs
provides the KPIs for the output including:
{
"assignedShifts": 8,
"unassignedShifts": 0,
"activatedEmployees": 2
}
2.2. Contracts with different priorities
In the following example, Ann and Beth have different contracts.
Ann’s contract has a higher priority than Beth’s contract, and Ann is less likely to be assigned shifts that break the rules in her contract. In this example, the overtime shifts are now assigned to Beth.

-
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": "Contracts with different priorities example"
}
},
"modelInput": {
"contracts": [
{
"id": "partTimeContractLimitOverTime",
"priority": "1",
"periodRules": [
{
"id": "Max24HoursNoOverTime",
"period": "WEEK",
"minutesWorkedMax": 1440,
"satisfiability": "PREFERRED"
}
]
},
{
"id": "partTimeContract",
"priority": "10",
"periodRules": [
{
"id": "Max24HoursPerWeekPartTime",
"period": "WEEK",
"minutesWorkedMax": 1440,
"satisfiability": "PREFERRED"
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"partTimeContractLimitOverTime"
]
},
{
"id": "Beth",
"contracts": [
"partTimeContract"
]
}
],
"shifts": [
{
"id": "Mon 1",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Mon 2",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
},
{
"id": "Tue 1",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Tue 2",
"start": "2027-02-02T09:00:00Z",
"end": "2027-02-02T17:00:00Z"
},
{
"id": "Wed 1",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Wed 2",
"start": "2027-02-03T09:00:00Z",
"end": "2027-02-03T17:00:00Z"
},
{
"id": "Overtime 1",
"start": "2027-02-04T09:00:00Z",
"end": "2027-02-04T17:00:00Z"
},
{
"id": "Overtime 2",
"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": "Contracts with different priorities example",
"submitDateTime": "2025-03-26T07:55:29.958954257Z",
"startDateTime": "2025-03-26T07:55:43.57733306Z",
"activeDateTime": "2025-03-26T07:55:43.788484857Z",
"completeDateTime": "2025-03-26T08:00:44.806417587Z",
"shutdownDateTime": "2025-03-26T08:00:45.042791782Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-1920soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 1",
"employee": "Ann"
},
{
"id": "Mon 2",
"employee": "Beth"
},
{
"id": "Tue 1",
"employee": "Ann"
},
{
"id": "Tue 2",
"employee": "Beth"
},
{
"id": "Wed 1",
"employee": "Ann"
},
{
"id": "Wed 2",
"employee": "Beth"
},
{
"id": "Overtime 1",
"employee": "Beth"
},
{
"id": "Overtime 2",
"employee": "Beth"
}
]
},
"inputMetrics": {
"employees": 2,
"shifts": 8,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 8,
"unassignedShifts": 0,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
"activatedEmployees": 2,
"assignedMandatoryShifts": 8,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput
contains the schedule with the additional shifts assigned to Beth
inputMetrics
provides a breakdown of the inputs in the input dataset.
KPIs
provides the KPIs for the output including:
{
"assignedShifts": 8,
"unassignedShifts": 0,
"activatedEmployees": 2
}
Next
-
Understand the constraints of the Employee Shift Scheduling model.
-
See the full API spec or try the online API.
-
Manage schedules with Time zones and Daylight Saving Time (DST) changes.