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

# Messages

> Give users detailed, plain-language updates while a roster is being created.

Messages are the detailed, plain-language side of
[status updates](/v2/concepts/status). Use them to give users a readable account
of the work in progress. For exact values, combine them with
[metrics](/v2/concepts/metrics).

Messages are AI-generated and can describe both the stage of the roster job and
its progress.

Each returned item contains Markdown text that you can add to a running feed in
your user interface. Show items in the order returned; their exact wording can
vary between runs.

<Info>
  Treat message text as display content. Do not use it to determine job state or
  drive application logic; use `status`, `hasResult`, and `isActive` for that.
</Info>

<Warning>
  Messages are an experimental feature and are only generated for
  integrators that have been enabled for experimental features.
</Warning>

## Add detailed updates to your interface

<Steps>
  <Step title="Enable messages and choose their language">
    Set `statusOptions.messages.isEnabled` to `true` in your `POST /roster/start` request. English is used when `language` is omitted.

    Also request metrics that reflect what your users care about. They give the AI verified numerical context and can make progress messages more specific. Choose focused scopes rather than every available metric.

    ```json title="Enable messages with a relevant metric" theme={null}
    {
      "statusOptions": {
        "metricScopes": [
          {
            "metricKey": "DEMAND.MISSING_SHIFTS_TO_MIN"
          }
        ],
        "messages": {
          "isEnabled": true,
          "language": "en"
        }
      }
    }
    ```

    See [Metrics](/v2/concepts/metrics) for the available metrics and scoping options.
  </Step>

  <Step title="Start the roster job">
    Send the roster start request and retain the returned `jobId`.
  </Step>
</Steps>

## Retrieve new messages while polling

Messages form an ordered stream. The status endpoint uses a token to
return only the new messages after your previous poll. Tokens are opaque
continuation values: do not decode, modify, or construct them. Keep one token per
roster job.

<Steps>
  <Step title="Initialize message retrieval">
    Call `GET /roster/status/{jobId}` without a `messageToken`. The response contains an empty `messages.items` array and the first `messages.nextToken`. Store that token.
  </Step>

  <Step title="Request new messages">
    Pass the stored token as the `messageToken` query parameter on the next poll. Append every returned item to your interface, then replace the stored token with `messages.nextToken`.
  </Step>

  <Step title="Keep polling">
    Repeat the previous step while `isActive` is `true`. Always store the returned token, even when `items` is empty, because the token can still advance.
  </Step>
</Steps>

<Tip>
  After the first request with a message token, keep polling
  `GET /roster/status/{jobId}` until `isActive` is `false`. Use `isActive`, not
  `status`, to decide when to stop polling. Always make that first token-bearing
  request, even if the initialization response already has `isActive: false`,
  so messages from a fast job are still retrieved.
</Tip>

This example shows how the token moves across multiple polls. Token values are shortened for readability.

| Poll | Request                | Returned messages | Returned token | What your client does                                                |
| ---- | ---------------------- | ----------------- | -------------- | -------------------------------------------------------------------- |
| 1    | No `messageToken`      | `[]`              | `token-1`      | Store `token-1`.                                                     |
| 2    | `messageToken=token-1` | Two items         | `token-2`      | Show both items and store `token-2`.                                 |
| 3    | `messageToken=token-2` | `[]`              | `token-3`      | Keep existing messages and store `token-3`.                          |
| 4    | `messageToken=token-3` | One item          | `token-4`      | Show the item, store `token-4`, and stop when `isActive` is `false`. |

<Tip>
  Persist the latest token with the job if polling can move between processes or
  resume after an application restart. Reusing an older token can return messages
  you have already received.
</Tip>
