API Documentation

Employees are the people you're scheduling. Each employee brings skills, belongs to teams, works under a contract, and has preferences about when they want to work.


Employee structure

{
  "id": 1,
  "name": "Jane Smith",
  "skills": [],
  "teams": [],
  "contract": {},
  "wishes": []
}

All fields are required except name, which is optional but helpful for debugging.

Skills

Skills represent what an employee can do-think "registered nurse" or "forklift certified". An employee can have multiple skills, and each can be time-bound:

{
  "skills": [
    {
      "id": 5,
      "start": "2024-01-01T00:00:00Z",
      "end": "2024-12-31T23:59:59Z"
    }
  ]
}

The solver will only assign an employee to shifts requiring skills they possess during that shift's time period. If start and end are omitted, the skill applies indefinitely.

For more on how skills work, see Mapping skills.

Teams

Teams group employees organizationally-departments, shifts, or any other grouping your organization uses. Like skills, team membership can be time-bound:

{
  "teams": [
    {
      "id": 2,
      "start": "2024-01-01T00:00:00Z",
      "end": "2024-03-31T23:59:59Z"
    }
  ]
}

The solver respects team requirements on spots, ensuring employees are only assigned where their team is allowed.

Contract

The contract defines labor rules and constraints for this employee. All fields are required and use minutes as the time unit:

{
  "contract": {
    "hoursBetweenShift": 660,
    "maxHoursDay": 600,
    "maxHoursWeek": 2280,
    "maxHoursMonth": 9600,
    "maxWorkDaysMonth": 20,
    "maxConsecutiveDays": 6,
    "minConsecutiveDays": 2,
    "weekendWorkFrequency": 2,
    "maxNhours": 2280,
    "minNhours": 1800,
    "inKWeeks": 4,
    "maxConsecutiveLateShifts": 3,
    "maxConsecutiveNightShifts": 3
  }
}

Key contract fields

  • hoursBetweenShift - Minimum rest between shifts (e.g., 660 = 11 hours)
  • maxHoursDay - Maximum work minutes in a 24-hour period
  • maxHoursWeek - Weekly limit (often legally mandated)
  • maxHoursMonth - Monthly limit
  • maxWorkDaysMonth - Maximum days with any shift assigned
  • maxConsecutiveDays / minConsecutiveDays - Control work streaks
  • weekendWorkFrequency - Work every N weekends (2 = every other weekend)
  • maxNhours / minNhours - Hours in a rolling window of inKWeeks weeks
  • maxConsecutiveLateShifts / maxConsecutiveNightShifts - Limit challenging shift patterns

The solver treats these as hard constraints when possible, or penalizes violations based on your settings.

Category shift quotas

You can cap or require a certain number of shifts with specific tag categories for each contract by using shiftQuotas:

{
  "contract": {
    "hoursBetweenShift": 660,
    "maxHoursDay": 600,
    "shiftQuotas": [
      {
        "id": 1,
        "departmentId": 10,
        "contractId": 99,
        "categoryTag": "night",
        "periodWeeks": 4,
        "minShifts": 2,
        "maxShifts": 4
      }
    ]
  }
}
  • categoryTag - Tag category (from your shiftTags) this quota applies to.
  • periodWeeks - Rolling window in weeks.
  • minShifts / maxShifts - Minimum and maximum number of shifts in that category for this contract over the window.

To enforce these quotas, enable the categoryShiftQuota setting, and optionally loadBalanceCategoryShifts to spread tagged shifts fairly across employees.

Competencies and seniority

Beyond simple skills, you can model more advanced qualifications:

{
  "skills": [
    {
      "id": 5,
      "seniorityLevel": 2
    }
  ],
  "competencies": [
    {
      "id": 1001,
      "start": "2024-01-01T00:00:00Z",
      "end": "2024-12-31T23:59:59Z"
    }
  ],
  "competencyUsers": [
    {
      "id": 501,
      "competencyId": 1001,
      "userId": 42,
      "validFrom": "2024-01-01T00:00:00Z",
      "validUntil": null
    }
  ]
}
  • seniorityLevel on skills lets you differentiate, for example, junior vs senior nurses. Spots can then specify a minSeniorityLevel (see Spots).
  • competencies / competencyUsers tie employees to more granular competency records which spots can require via requiredCompetencies.

To activate these constraints, set weights for the competencyRequired and minSeniorityLevel settings. With zero weights, the solver ignores competencies and minimum seniority even if you send the fields.

Wishes

Wishes express when an employee prefers to work or not work. There are three types:

{
  "wishes": [
    {
      "type": "DESIRED",
      "start": "2024-03-15T09:00:00Z",
      "end": "2024-03-15T17:00:00Z"
    },
    {
      "type": "UNAVAILABLE",
      "start": "2024-03-20T00:00:00Z",
      "end": "2024-03-20T23:59:59Z"
    },
    {
      "type": "UNDESIRED",
      "start": "2024-03-25T00:00:00Z",
      "end": "2024-03-25T23:59:59Z"
    }
  ]
}
  • DESIRED - Employee wants to work during this period
  • UNAVAILABLE - Employee cannot work (vacation, medical appointment, etc.)
  • UNDESIRED - Employee prefers not to work but can if needed

The solver prioritizes these wishes according to your settings. UNAVAILABLE is treated as a hard constraint; DESIRED and UNDESIRED are soft constraints that influence the solution.


Example employee

Here's a complete example:

{
  "id": 42,
  "name": "Dr. Sarah Chen",
  "skills": [
    {"id": 10},
    {"id": 12, "start": "2024-01-01T00:00:00Z"}
  ],
  "teams": [
    {"id": 3}
  ],
  "contract": {
    "hoursBetweenShift": 660,
    "maxHoursDay": 600,
    "maxHoursWeek": 2280,
    "maxHoursMonth": 9600,
    "maxWorkDaysMonth": 20,
    "maxConsecutiveDays": 6,
    "minConsecutiveDays": 2,
    "weekendWorkFrequency": 3,
    "maxNhours": 2280,
    "minNhours": 1800,
    "inKWeeks": 4,
    "maxConsecutiveLateShifts": 3,
    "maxConsecutiveNightShifts": 2
  },
  "wishes": [
    {
      "type": "UNAVAILABLE",
      "start": "2024-03-15T00:00:00Z",
      "end": "2024-03-17T23:59:59Z"
    }
  ]
}

This employee has two skills (one recently acquired), works in one team, has standard healthcare worker constraints, and is unavailable for a three-day period.