Skip to main content
v2 keeps the same core rostering concepts, but the API surface has been cleaned up considerably.

Before you migrate

Before updating your v1 integration code, make sure your v2 access is in place.
  • Request a new Automatic Rostering integration in the Visma Developer Portal. See Authentication for the full application setup, integration request, and credential flow.
  • Regenerate your API types or client code from the current v2 OpenAPI specification at /openapi.yaml. This helps catch renamed fields such as jobInfocontext and constraintsrules early in your migration.
The biggest shifts are:
  • /jobs becomes the /roster/* workflow
  • jobInfo becomes context
  • constraints become rules
  • configuration moves into extensions

API workflow

v1v2What changed
POST /jobsPOST /roster/startStarts a roster job
GET /jobs/{id}GET /roster/status/{jobId}Status response shape changed
GET /jobs/{id}/resultGET /roster/result/{jobId}Can now return 202 Accepted while processing
PUT /jobs/{id}POST /roster/stop/{jobId}Stop endpoint moved and changed method
The v2 workflow is a little more explicit than v1:
Start calls return only the jobId
{
  "jobId": "b6a4d60d-5f15-4cb6-8f1d-f6f0f72d243f"
}
Status calls return updatedAt, status, and hasResult. hasResult indicates whether calling the result endpoint will produce anything.
{
  "jobId": "b6a4d60d-5f15-4cb6-8f1d-f6f0f72d243f",
  "updatedAt": "2026-01-01T12:00:00Z",
  "status": "running",
  "hasResult": true
}
Result calls can return 202 Accepted while no result is available yet
{
  "message": "Result is not yet available.",
  "jobId": "b6a4d60d-5f15-4cb6-8f1d-f6f0f72d243f"
}

Request payload

The fastest way to understand the migration is to compare the top-level payloads.
{
  "jobInfo": {
    "id": "plan-123",
    "organisationId": "org-123",
    "scheduleType": "CALENDAR",
    "demandType": "SHIFT_DEMAND",
    "planningHorizon": {
      "startDate": "2026-01-01",
      "endDate": "2026-01-31",
      "fteStartDay": {
        "dayIndex": 0
      },
      "fteEndDay": {
        "dayIndex": 30
      }
    }
  },
  "employees": [
    {
      "id": "employee-1"
    }
  ],
  "shifts": [
    {
      "id": "day-shift",
      "intervals": [
        {
          "startTime": "09:00",
          "endTime": "17:00",
          "dayIndicator": 0
        }
      ],
      "connectedShiftsNextDay": ["handover-shift"]
    }
  ],
  "demands": [
    {
      "days": {
        "dates": ["2026-01-01", "2026-01-02"]
      },
      "shiftDemands": [
        {
          "shiftId": "day-shift",
          "ideal": 1
        }
      ]
    }
  ],
  "constraints": {
    "employeeAvailabilityConstraints": [
      {
        "id": "avail-1",
        "importance": "HIGH",
        "isDesired": true,
        "periods": {
          "days": {
            "daysOfWeek": ["MON", "TUE", "WED", "THU", "FRI"],
            "startTime": "09:00",
            "endTime": "17:00"
          }
        }
      }
    ]
  },
  "configuration": {
    "labels": {
      "periods": [
        {
          "label": "weekend",
          "periods": {
            "days": {
              "daysOfWeek": ["SAT", "SUN"]
            }
          }
        }
      ]
    },
    "fteBelongsToShift": true,
    "bonusTimeSettings": [
      {
        "bonusMinutesPerHour": 30
      }
    ]
  }
}
{
  "context": {
    "planId": "plan-123",
    "identity": {
      "tenantId": "tenant-123",
      "userId": "user-456"
    },
    "horizon": {
      "startDate": "2026-01-01",
      "endDate": "2026-01-31",
      "scheduleType": "CALENDAR"
    },
    "demandType": "SHIFT_DEMAND"
  },
  "employees": [
    {
      "id": "employee-1"
    }
  ],
  "shifts": [
    {
      "id": "day-shift",
      "intervals": [
        {
          "startTime": "09:00",
          "endTime": "17:00",
          "dayIndicator": 0
        }
      ]
    }
  ],
  "demands": [
    {
      "days": {
        "dates": ["2026-01-01", "2026-01-02"]
      },
      "shiftDemands": [
        {
          "shiftId": "day-shift",
          "ideal": 1
        }
      ]
    }
  ],
  "rules": {
    "availabilityRules": [
      {
        "id": "avail-1",
        "importance": "HIGH",
        "isDesired": true,
        "periods": {
          "days": {
            "daysOfWeek": ["MON", "TUE", "WED", "THU", "FRI"],
            "startTime": "09:00",
            "endTime": "17:00"
          }
        }
      }
    ]
  },
  "extensions": {
    "labeling": {
      "periods": [
        {
          "label": "weekend",
          "periods": {
            "days": {
              "daysOfWeek": ["SAT", "SUN"]
            }
          }
        }
      ]
    },
    "timeAccounting": {
      "horizon": {
        "startDay": {
          "dayIndex": 0
        },
        "endDay": {
          "dayIndex": 30
        },
        "includeFullShifts": true
      },
      "bonusTimeSettings": [
        {
          "bonusMinutesPerHour": 30
        }
      ]
    }
  }
}

Top-level field mapping

v1v2Notes
jobInfo.idcontext.planIdplanId is used to indicate that multiple jobs solved for the same plan
customer_id and user_id headerscontext.identity.tenantId context.identity.userIdIdentity context is now sent in body instead of headers
jobInfo.planningHorizoncontext.horizonHorizon is now grouped under context
jobInfo.demandTypecontext.demandTypeSame concept, new location
constraintsrulesAll rule collections were renamed
configuration.labelsextensions.labelingLabel definitions moved into extensions
configuration.bonusTimeRulesextensions.timeAccounting.bonusTimeSettingsTime-accounting settings moved under extensions
configuration.defaultTimeRulesextensions.timeAccounting.defaultTimeSettingsSame semantics, new location
configuration.fteBelongsToShiftextensions.timeAccounting.horizon.includeFullShiftsSame intent, more explicit naming
jobInfo.planningHorizon.fteStartDayextensions.timeAccounting.horizon.startDayMoved out of jobInfo.horizon
jobInfo.planningHorizon.fteEndDayextensions.timeAccounting.horizon.endDayMoved out of jobInfo.horizon
The v1 field planningHorizon.nrOfWeeks does not exist in the v2 contract. Build your v2 solve horizon with startDate, endDate, and scheduleType. Note that this now makes it possible to create recurring schedules that start on different days than Monday (though the horizon should still be a multiple of 7 days).

Constraints are now rules

Most of the solver model is still familiar, but the terminology has changed consistently from constraint to rule.
v1 collectionv2 collection
employeeAvailabilityConstraintsavailabilityRules
employeeUtilizationConstraintsutilizationRules
cooldownConstraintscooldownRules
consecutiveConstraintsconsecutiveRules
patternConstraintspatternRules
periodicRestConstraintsperiodicRestRules
periodDistributionConstraintsperiodDistributionRules
layoutConstraintslayoutRules
rotationConstraintsrotationRules
fairnessConstraintsfairnessRules
The enum values for importance remain the same in v2, including STRICT.

Rule payload changes to watch

Beyond the constraint to rule rename, v2 also uses grouped fields more consistently. The main pattern is that target values now live under targets and advanced configuration now lives under options.
  • bonusTimeoptions.bonusTime
  • overlapRulesoptions.overlapSettings
  • emptyDayBehavioursoptions.emptyDayBehaviours
  • blockedPeriodsoptions.blockedPeriods
  • periodGroupsoptions.periodGroups
  • minWorkedPeriodstargets.minWorkedPeriods
  • maxWorkedPeriodstargets.maxWorkedPeriods
  • maxConsecutiveWorkedPeriodstargets.maxConsecutiveWorkedPeriods
  • minSurroundingFreePeriodstargets.minSurroundingFreePeriods
  • overlapRulesoptions.overlapSettings
  • filters.constraintsfilters.rules
  • applyConstraintImportanceScalingapplyRuleImportanceScaling
  • constraintFactorsruleFactors

Concepts being reworked for v2

If you currently rely on shiftTemplates, connectedShiftsPreviousDay, or connectedShiftsNextDay, do not send those fields to the current v2 API. They are not available yet, even though the concepts themselves are still planned.
Treat these concepts as temporarily unavailable rather than permanently gone:
  • shiftTemplates are not yet exposed in the current v2 OpenAPI contract
  • connectedShiftsPreviousDay and connectedShiftsNextDay are also not part of the current v2 OpenAPI contract
  • If your v1 integration depends on these concepts, keep your migration layer flexible so you can adopt the new v2 implementation once it lands

Continue with v2

Quickstart

Build a fresh v2 roster request from scratch.

Rules

Browse the v2 rule model in more detail.