---
title: "Schedule aktualisieren"
description: "Name, Zeitzone, Gültigkeitszeitraum, Wochenfenster, Rotationskadenz und Rotationsmitglieder eines Bereitschaftsplans ändern — in einem atomaren Aufruf."
---

`PATCH /api/im/schedules/:id`

Hier wird die Rotation eines Schedules tatsächlich konfiguriert. [Das Anlegen eines Schedules](./schedules) liefert eine leere Hülle (`rotationMode: "none"`, keine Mitglieder); dieser Endpunkt setzt Kadenz, Wochenfenster und die Rotationsbesetzung.

Jedes Feld ist **optional**. Nur die im Body vorhandenen Felder werden angefasst — ein Body `{ "name": "Primär" }` benennt den Schedule um und ändert sonst nichts.

## Authentifizierung

Erfordert den Basiszugriff auf Incident Management, den jeder Endpunkt dieser API braucht, plus die Schreibhürde: Deine Rolle muss `admin` sein, oder du musst Team-Admin des Teams sein, zu dem der Schedule gehört. Ein organisationsweites API-Token gilt als Organisations-Admin.

<Callout type="warn">
Incident Management ist derzeit auf Plattform-Administratoren beschränkt. Solange diese Beschränkung gilt, erhalten Organisationsrollen und organisationsweite API-Tokens auf jedem `/api/im/**`-Endpunkt `403 imAccessDenied` — auch auf diesem.
</Callout>

## Request-Body

| Feld | Typ | Beschreibung |
|-------|------|-------------|
| `name` | string | Name des Schedules, bis zu 120 Zeichen. |
| `timezone` | string | IANA-Zeitzone (z. B. `Europe/Berlin`). Jede Übergabegrenze und jedes Wochenfenster wird in dieser Zone ausgewertet, auch über die Sommerzeit hinweg. |
| `effectiveFrom` | string \| null | ISO-Zeitstempel. Vorher alarmiert der Schedule niemanden. `null` = keine Startgrenze. |
| `effectiveUntil` | string \| null | ISO-Zeitstempel. Danach alarmiert der Schedule niemanden. `null` = keine Endgrenze. |
| `weeklySchedules` | array | Wiederkehrende Bereitschaftsfenster, bis zu 50. Jeweils: `{ from: "HH:mm", until: "HH:mm", days: number[] }`, `days` als ISO-Wochentage (1 = Montag .. 7 = Sonntag). `until` darf `"24:00"` für Tagesende sein; ein `until` gleich oder vor `from` reicht über Mitternacht hinaus. Ein leeres Array bedeutet 24/7. |
| `rotations` | array | **Vollständiger Ersatz** der Rotationsgruppen, bis zu 50. Jeweils: `{ members: string[] }`, bis zu 200 Mitglieder. Die Array-Reihenfolge ist die Rotationsreihenfolge, die Reihenfolge innerhalb einer Gruppe bleibt erhalten. Jedes Mitglied muss bereits im Team des Schedules sein. Feld weglassen lässt die Rotationen unberührt — ein `[]` entfernt alle. |

Dazu die Kadenzfelder — `rotationMode`, `rotationRepeats`, `customRepeatUnit`, `customRepeatValue`, `autoRotationSize`, `roundRobinSize`, `startsOnTime`, `startsOnDayOfWeek`, `startsOnDateOfMonth`. Sie sind mitsamt ihren erlaubten Werten einmal unter [Rotationskadenz](./schedules#rotationskadenz) dokumentiert.

`teamId` und `tierId` sind **nicht** patchbar. Einen Schedule zwischen Teams oder Stufen zu verschieben würde stillschweigend umlenken, wen er alarmiert — das ist keine Teilaktualisierung.

### Wie die Kadenz validiert wird

Kadenzfelder werden auf die aktuelle Zeile des Schedules gemergt und dann **als Ganzes** validiert, nicht Feld für Feld. Genau das erlaubt es, ein einzelnes Feld zu patchen — etwa `roundRobinSize` —, ohne die restliche Kadenz erneut zu senden, und trotzdem eine unmögliche Kombination abzulehnen (zum Beispiel `rotationRepeats: "weekly"` ohne ein `startsOnDayOfWeek` irgendwo in der effektiven Konfiguration).

Die Validierung läuft, bevor irgendetwas geschrieben wird. Eine Kadenz, an der sich der Materializer verschlucken würde, erreicht die Datenbank nie.

### Wann Schichten neu berechnet werden

Änderungen an Zeitzone, Gültigkeitszeitraum, Wochenfenstern, einem Kadenzfeld oder den Rotationen lösen eine Neuberechnung der Schichten aus. Eine reine Umbenennung nicht — sie würde die Sperre des Schedules ziehen und Zeilen ohne Grund neu schreiben.

## Beispiel (cURL)

```bash
curl -X PATCH "$BASE_URL/api/im/schedules/7" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rotationMode": "explicit",
    "rotationRepeats": "custom",
    "customRepeatUnit": "minutes",
    "customRepeatValue": 30,
    "startsOnTime": "09:00",
    "rotations": [
      { "members": ["u_abc123"] },
      { "members": ["u_def456"] }
    ]
  }'
```

## Response

`200 OK`: die Konfiguration des Schedules nach der Änderung.

```json
{
  "id": 7,
  "displayName": "Primary On-Call",
  "timezone": "Europe/Berlin",
  "effectiveFrom": "2026-08-01T00:00:00.000Z",
  "effectiveUntil": null,
  "weeklySchedules": [],
  "rotationMode": "explicit",
  "rotationRepeats": "custom",
  "customRepeatUnit": "minutes",
  "customRepeatValue": 30,
  "autoRotationSize": null,
  "roundRobinSize": 1,
  "startsOnDayOfWeek": null,
  "startsOnDateOfMonth": null,
  "startsOnTime": "09:00",
  "rotations": [
    {
      "id": 12,
      "rotationOrder": 1,
      "members": [{ "userId": "u_abc123", "userName": "Ada Lovelace", "memberOrder": 1 }]
    },
    {
      "id": 13,
      "rotationOrder": 2,
      "members": [{ "userId": "u_def456", "userName": "Bob Fixit", "memberOrder": 1 }]
    }
  ]
}
```

Der Schlüssel `rotations` ist **nur enthalten, wenn du `rotations` gesendet hast**. Eine Anfrage, die sie nicht angefasst hat, lässt ihn ganz weg, statt einen Zustand nachzulesen, den du nicht geändert hast; für den aktuellen Rotationsstand gibt es `GET /api/im/teams/:id/escalations`.

## Häufige Fehler

| Status | `data.code` | Ursache |
|--------|-------------|---------|
| 400 | `invalidRequestBody` | Nicht-numerische `:id`, fehlender oder zu langer `name`, ungültige `timezone` oder ein fehlerhafter `rotations`-Eintrag (kein Objekt, `members` kein Array, leere User-ID). |
| 403 | `imAccessDenied` | Kein Zugriff auf Incident Management — siehe Hinweis unter Authentifizierung. |
| 403 | `imTeamWriteDenied` | IM-Zugriff vorhanden, aber weder Organisations-Admin noch Team-Admin des Teams dieses Schedules. |
| 404 | `imScheduleNotFound` | Kein solcher Schedule in deiner Organisation. |
| 404 | `imTeamMemberNotFound` | Eine User-ID in `rotations` ist kein Mitglied des Teams. |
| 422 | `imInvalidRotationMode` | `rotationMode` ist nicht `none`, `auto` oder `explicit`. |
| 422 | `imInvalidRotation` | Die Kadenz passt nicht zusammen — unbekanntes `rotationRepeats` oder `customRepeatUnit`, `startsOnDateOfMonth` außerhalb 1–31, ein für die effektive Kadenz erforderliches Feld fehlt, zu viele Rotationen oder Mitglieder, oder eine doppelte User-ID innerhalb einer Gruppe. |
| 422 | `imInvalidNumber` | `customRepeatValue`, `autoRotationSize` oder `roundRobinSize` ist keine Ganzzahl ≥ 1. |
| 422 | `imInvalidTimeOfDay` | `startsOnTime` oder `from`/`until` eines Wochenfensters ist nicht `"HH:mm"`. |
| 422 | `imInvalidDayOfWeek` | `startsOnDayOfWeek` oder ein Tag in `weeklySchedules` ist kein ISO-Wochentag 1–7. |
| 422 | `imInvalidTimeFilter` | `weeklySchedules` ist kein Array, hat mehr als 50 Einträge, oder ein Eintrag ist kein Objekt. |
