> ## Documentation Index
> Fetch the complete documentation index at: https://docs.automaticrostering.visma.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from v1

> Upgrade your integration from the v1 API to the v2 API.

<Info>
  v2 keeps the same core rostering concepts, but the API surface has been
  cleaned up considerably.
</Info>

## 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](/v2/getting-started/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`](/openapi.yaml). This helps catch renamed fields such as `jobInfo` → `context` and `constraints` → `rules` 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

| v1                      | v2                           | What changed                                   |
| ----------------------- | ---------------------------- | ---------------------------------------------- |
| `POST /jobs`            | `POST /roster/start`         | Starts a roster job                            |
| `GET /jobs/{id}`        | `GET /roster/status/{jobId}` | Status response shape changed                  |
| `GET /jobs/{id}/result` | `GET /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:

<AccordionGroup>
  <Accordion title="Start response">
    Start calls return only the `jobId`

    ```json theme={null}
    {
      "jobId": "b6a4d60d-5f15-4cb6-8f1d-f6f0f72d243f"
    }
    ```
  </Accordion>

  <Accordion title="Status response">
    Status calls return `updatedAt`, `status`, and `hasResult`. `hasResult` indicates whether calling the result endpoint will produce anything.

    ```json theme={null}
    {
      "jobId": "b6a4d60d-5f15-4cb6-8f1d-f6f0f72d243f",
      "updatedAt": "2026-01-01T12:00:00Z",
      "status": "running",
      "hasResult": true
    }
    ```
  </Accordion>

  <Accordion title="Result polling">
    Result calls can return `202 Accepted` while no result is available yet

    ```json theme={null}
    {
      "message": "Result is not yet available.",
      "jobId": "b6a4d60d-5f15-4cb6-8f1d-f6f0f72d243f"
    }
    ```
  </Accordion>
</AccordionGroup>

## Request payload

The fastest way to understand the migration is to compare the top-level payloads.

<AccordionGroup>
  <Accordion title="v1 payload shape">
    ```json theme={null}
    {
      "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
          }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="v2 payload shape">
    ```json theme={null}
    {
      "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
            }
          ]
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Top-level field mapping

| v1                                    | v2                                                    | Notes                                                                    |
| ------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------ |
| `jobInfo.id`                          | `context.planId`                                      | `planId` is used to indicate that multiple jobs solved for the same plan |
| `customer_id` and `user_id` headers   | `context.identity.tenantId` `context.identity.userId` | Identity context is now sent in body instead of headers                  |
| `jobInfo.planningHorizon`             | `context.horizon`                                     | Horizon is now grouped under `context`                                   |
| `jobInfo.demandType`                  | `context.demandType`                                  | Same concept, new location                                               |
| `constraints`                         | `rules`                                               | All rule collections were renamed                                        |
| `configuration.labels`                | `extensions.labeling`                                 | Label definitions moved into extensions                                  |
| `configuration.bonusTimeRules`        | `extensions.timeAccounting.bonusTimeSettings`         | Time-accounting settings moved under `extensions`                        |
| `configuration.defaultTimeRules`      | `extensions.timeAccounting.defaultTimeSettings`       | Same semantics, new location                                             |
| `configuration.fteBelongsToShift`     | `extensions.timeAccounting.horizon.includeFullShifts` | Same intent, more explicit naming                                        |
| `jobInfo.planningHorizon.fteStartDay` | `extensions.timeAccounting.horizon.startDay`          | Moved out of `jobInfo.horizon`                                           |
| `jobInfo.planningHorizon.fteEndDay`   | `extensions.timeAccounting.horizon.endDay`            | Moved out of `jobInfo.horizon`                                           |

<Note>
  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).
</Note>

## Constraints are now rules

Most of the solver model is still familiar, but the terminology has changed consistently from `constraint` to `rule`.

| v1 collection                     | v2 collection             |
| --------------------------------- | ------------------------- |
| `employeeAvailabilityConstraints` | `availabilityRules`       |
| `employeeUtilizationConstraints`  | `utilizationRules`        |
| `cooldownConstraints`             | `cooldownRules`           |
| `consecutiveConstraints`          | `consecutiveRules`        |
| `patternConstraints`              | `patternRules`            |
| `periodicRestConstraints`         | `periodicRestRules`       |
| `periodDistributionConstraints`   | `periodDistributionRules` |
| `layoutConstraints`               | `layoutRules`             |
| `rotationConstraints`             | `rotationRules`           |
| `fairnessConstraints`             | `fairnessRules`           |

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`.

<AccordionGroup>
  <Accordion title="Utilization">
    * `bonusTime` → `options.bonusTime`
    * `overlapRules` → `options.overlapSettings`
  </Accordion>

  <Accordion title="Pattern">
    * `emptyDayBehaviours` → `options.emptyDayBehaviours`
  </Accordion>

  <Accordion title="Periodic Rest">
    * `blockedPeriods` → `options.blockedPeriods`
    * `periodGroups` → `options.periodGroups`
  </Accordion>

  <Accordion title="Period Distribution">
    * `minWorkedPeriods` → `targets.minWorkedPeriods`
    * `maxWorkedPeriods` → `targets.maxWorkedPeriods`
    * `maxConsecutiveWorkedPeriods` → `targets.maxConsecutiveWorkedPeriods`
    * `minSurroundingFreePeriods` → `targets.minSurroundingFreePeriods`
    * `overlapRules` → `options.overlapSettings`
  </Accordion>

  <Accordion title="Fairness">
    * `filters.constraints` → `filters.rules`
    * `applyConstraintImportanceScaling` → `applyRuleImportanceScaling`
    * `constraintFactors` → `ruleFactors`
  </Accordion>
</AccordionGroup>

## Concepts being reworked for v2

<Warning>
  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.
</Warning>

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

<Columns cols={2}>
  <Card title="Quickstart" icon="circle-play" href="/getting-started/quickstart">
    Build a fresh v2 roster request from scratch.
  </Card>

  <Card title="Rules" icon="shield-check" href="/rules/index">
    Browse the v2 rule model in more detail.
  </Card>
</Columns>
