Shift tag types
Shifts can be assigned to employees based on tag.
Tags provide additional information about employees and shifts. For example, a tag could be a country such as "Belgium", a department "Accounting", an employment type "Contractor", or a task "Reporting".
Tags can be grouped into tag types. A tag type could be "Country", "Department", "Employment Type", or "Task".
When declaring Tag Types and Tags, tagTypes must be declared before tags.
|
{
"modelInput": {
"tagTypes": [
{
"id": "Task"
}
],
"tags": [
{
"id": "Task A",
"tagType": "Tasks"
},
{
"id": "Task B",
"tagType": "Tasks"
},
{
"id": "Task C",
"tagType": "Tasks"
}
]
}
}
Shift tag match rules allow you to specify if matching the tags is required or preferred. In the case of preferred matches you can define multipliers for different tag types when they are matched, these multipliers allow you give more weight to some matches over others.
This is useful when it is preferable to match tag types in order of preference, for instance, match tag type 1 first, if this isn’t possible, match tag type 2 second, and so on.
For employees that are organized into teams and departments, it might be preferable to assign employees to shifts with their team, and if that’s not possible assign them to shifts in their department.
This guide explains assigning employees to shifts with shift tags:
1. Assign employees to shifts with required shift tags
Learn how to configure an API Key to run the examples in this guide:
In the examples, replace |
For an organization that is divided into departments where employees are only assigned shifts to the department they belong to, we define a tag hierarchy:
{
"tagTypes": [
{
"id": "Department"
}
],
"tags": [
{
"id": "Department A",
"tagType": "Department"
},
{
"id": "Department B",
"tagType": "Department"
}
]
}
Shifts must reference the department tag they belong to:
{
"shifts": [
{
"id": "Mon A",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Department A" ]
},
{
"id": "Mon B",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Department B" ]
}
]
}
Employees must specify which department they can work in with the requiredShiftTags attribute:
{
"employees": [
{
"id": "Ann",
"requiredShiftTags": [ "Department A" ]
},
{
"id": "Beth",
"requiredShiftTags": [ "Department B" ]
}
]
}
Shift tag match rules are defined as part of the global rules configuration.
{
"modelInput": {
"globalRules": {
"shiftTagMatchRules": [
{
"id": "matchDepartment",
"satisfiability": "REQUIRED"
}
]
}
}
}
The satisfiability of the rule can be REQUIRED or PREFERRED.
When the satisfiability of the shift tag match rule is Required the Employee works shifts with non-matching required shift tags hard constraint makes sure the employees are assigned to shifts with the correct required shift tags.
Shifts wil not be assigned if assigning them breaks this constraint.
In the following example, there are 2 shifts (1 in Department A and 1 in Department B), and 2 employees. Ann can work in Department A, and Beth can work in Department B.
Both employees are assigned to shifts in the correct department.
-
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 shift tags example"
}
},
"modelInput": {
"tagTypes": [
{
"id": "Department"
}
],
"tags": [
{
"id": "Department A",
"tagType": "Department"
},
{
"id": "Department B",
"tagType": "Department"
}
],
"globalRules": {
"shiftTagMatchRules": [
{
"id": "matchDepartment",
"satisfiability": "REQUIRED"
}
]
},
"employees": [
{
"id": "Ann",
"requiredShiftTags": [ "Department A" ]
},
{
"id": "Beth",
"requiredShiftTags": [ "Department B" ]
}
],
"shifts": [
{
"id": "Mon A",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Department A" ]
},
{
"id": "Mon B",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Department 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": "ID",
"originId": "ID",
"name": "Required shift tags example",
"submitDateTime": "2026-01-05T07:30:01.960482446Z",
"startDateTime": "2026-01-05T07:30:09.103799638Z",
"activeDateTime": "2026-01-05T07:30:09.19116669Z",
"completeDateTime": "2026-01-05T07:30:39.497218983Z",
"shutdownDateTime": "2026-01-05T07:30:39.497223503Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/0soft",
"tags": [
"system.type:from-request",
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon A",
"employee": "Ann"
},
{
"id": "Mon B",
"employee": "Beth"
}
],
"employees": [
{
"id": "Ann",
"metrics": {
"assignedShifts": 1,
"durationWorked": "PT8H"
}
},
{
"id": "Beth",
"metrics": {
"assignedShifts": 1,
"durationWorked": "PT8H"
}
}
]
},
"inputMetrics": {
"employees": 2,
"shifts": 2,
"pinnedShifts": 0,
"mandatoryShifts": 2,
"optionalShifts": 0
},
"kpis": {
"assignedShifts": 2,
"unassignedShifts": 0,
"disruptionPercentage": 0,
"activatedEmployees": 2,
"assignedMandatoryShifts": 2
},
"run": {
"id": "ID",
"originId": "ID",
"name": "Required shift tags example",
"submitDateTime": "2026-01-05T07:30:01.960482446Z",
"startDateTime": "2026-01-05T07:30:09.103799638Z",
"activeDateTime": "2026-01-05T07:30:09.19116669Z",
"completeDateTime": "2026-01-05T07:30:39.497218983Z",
"shutdownDateTime": "2026-01-05T07:30:39.497223503Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/0soft",
"tags": [
"system.type:from-request",
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
}
}
2. Assign employees to shifts with preferred shift tags
When shifts are assigned to employees with cascading priorities, the satisfiability of the shift tag match rules can be set to Preferred.
This makes it possible to assign employees to shifts in the following way:
-
If possible assign the employee to a shift with a specific team.
-
If the team assignment is not possible, assign the employee to a specific department.
-
If the team and department assignment are not possible, assign the employee to a shift in a specific location.
The following tag hierarchy would be used for these cascading priorities:
{
"tagTypes": [
{
"id": "Department"
},
{
"id": "Team"
},
{
"id": "Location"
}
],
"tags": [
{
"id": "Team X",
"tagType": "Team"
},
{
"id": "Team Y",
"tagType": "Team"
},
{
"id": "Department A",
"tagType": "Department"
},
{
"id": "Department B",
"tagType": "Department"
},
{
"id": "Location 1",
"tagType": "Location"
},
{
"id": "Location 2",
"tagType": "Location"
}
]
}
When the shift tag match rule’s satisfiability is PREFERRED, employees define preferredShiftTags:
{
"employees": [
{
"id": "Ann",
"preferredShiftTags": [ "Department A", "Team X", "Location 1" ]
},
{
"id": "Beth",
"preferredShiftTags": [ "Department A", "Team X", "Location 1" ]
},
{
"id": "Carl",
"preferredShiftTags": [ "Department A", "Team X", "Location 1" ]
}
]
}
Shifts include the shifts tag:
{
"shifts": [
{
"id": "Mon A",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Team X" ]
},
{
"id": "Mon B",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Department A" ]
},
{
"id": "Mon C",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Location 1" ]
}
]
}
The shift tag match rule includes a tagTypeMatchMultipliers for each tag type:
{
"shiftTagMatchRules": [
{
"id": "MatchOrganization",
"satisfiability": "PREFERRED",
"tagTypeMatchMultipliers": {
"Team": 100000,
"Department": 10000,
"Location": 1000
}
}
]
}
When the satisfiability fo the rule is PREFERRED, the Employee works shift with preferred shift tags soft constraint is invoked.
A soft reward is applied to the dataset score when an employee is assigned to a shift with their preferred shift tag.
The reward is derived from the value of the tagTypeMatchMultipliers for the tag type that was matched.
Tags of a tag type with a higher tagTypeMatchMultipliers will be matched first, as Timefold is incentivized to use solutions with the best score.
In the following example, there are 3 employees with the same preferred shift tags. There are 3 shifts, each shift has a different shift tag type. All three shifts are assigned and a soft reward of is added to the dataset score for each shift tag that is matched:
-
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 shift tags example"
}
},
"modelInput": {
"tagTypes": [
{
"id": "Department"
},
{
"id": "Team"
},
{
"id": "Location"
}
],
"tags": [
{
"id": "Team X",
"tagType": "Team"
},
{
"id": "Team Y",
"tagType": "Team"
},
{
"id": "Department A",
"tagType": "Department"
},
{
"id": "Department B",
"tagType": "Department"
},
{
"id": "Location 1",
"tagType": "Location"
},
{
"id": "Location 2",
"tagType": "Location"
}
],
"globalRules": {
"shiftTagMatchRules": [
{
"id": "MatchOrganization",
"satisfiability": "PREFERRED",
"tagTypeMatchMultipliers": {
"Team": 100000,
"Department": 10000,
"Location": 1000
}
}
]
},
"employees": [
{
"id": "Ann",
"preferredShiftTags": [ "Department A", "Team X", "Location 1" ]
},
{
"id": "Beth",
"preferredShiftTags": [ "Department A", "Team X", "Location 1" ]
},
{
"id": "Carl",
"preferredShiftTags": [ "Department A", "Team X", "Location 1" ]
}
],
"shifts": [
{
"id": "Mon A",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Team X" ]
},
{
"id": "Mon B",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Department A" ]
},
{
"id": "Mon C",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": [ "Location 1" ]
}
]
}
}
| 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": "ID",
"originId": "ID",
"name": "Preferred shift tags example",
"submitDateTime": "2026-01-07T08:17:39.699372725Z",
"startDateTime": "2026-01-07T08:17:46.753541571Z",
"activeDateTime": "2026-01-07T08:17:46.86171546Z",
"completeDateTime": "2026-01-07T08:18:17.290267207Z",
"shutdownDateTime": "2026-01-07T08:18:17.290277227Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/111000soft",
"tags": [
"system.type:from-request",
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon A",
"employee": "Ann"
},
{
"id": "Mon B",
"employee": "Beth"
},
{
"id": "Mon C",
"employee": "Carl"
}
],
"employees": [
{
"id": "Ann",
"metrics": {
"assignedShifts": 1,
"durationWorked": "PT8H",
"durationOfTimePreferencesMet": "PT8H"
}
},
{
"id": "Beth",
"metrics": {
"assignedShifts": 1,
"durationWorked": "PT8H",
"durationOfTimePreferencesMet": "PT8H"
}
},
{
"id": "Carl",
"metrics": {
"assignedShifts": 1,
"durationWorked": "PT8H",
"durationOfTimePreferencesMet": "PT8H"
}
}
]
},
"inputMetrics": {
"employees": 3,
"shifts": 3,
"pinnedShifts": 0,
"mandatoryShifts": 3,
"optionalShifts": 0
},
"kpis": {
"assignedShifts": 3,
"unassignedShifts": 0,
"disruptionPercentage": 0,
"averageDurationOfEmployeesPreferencesMet": "PT8H",
"minimumDurationOfPreferencesMetAcrossEmployees": "PT8H",
"activatedEmployees": 3,
"assignedMandatoryShifts": 3
},
"run": {
"id": "ID",
"originId": "ID",
"name": "Preferred shift tags example",
"submitDateTime": "2026-01-07T08:17:39.699372725Z",
"startDateTime": "2026-01-07T08:17:46.753541571Z",
"activeDateTime": "2026-01-07T08:17:46.86171546Z",
"completeDateTime": "2026-01-07T08:18:17.290267207Z",
"shutdownDateTime": "2026-01-07T08:18:17.290277227Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/111000soft",
"tags": [
"system.type:from-request",
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
}
}
Next
-
See the full API spec or try the online API.
-
Learn more about employee shift scheduling from our YouTube playlist.
-
See other options related to Shift type diversity.