# Maintenance
Planned maintenance windows, which pause alerts and show on status pages.
**Common tasks**
- [Plan a maintenance window](#post-organizations-organization-maintenance-windows)
- [Mark it complete](#patch-organizations-organization-maintenance-windows-maintenancewindow-complete)
**Only in the app:** Nothing. Maintenance windows can be fully managed with a token.
**How it works in the app:** [help article](https://infranest.io/docs/maintenance).
**Scopes:** Read with `monitoring.read`, change with `monitoring.write`. See [Tokens and scopes](../tokens-and-scopes.md#scopes).
[Maintenance windows](#maintenance-windows) 6
Every endpoint below takes a token in the `Authorization: Bearer` header and answers JSON. Errors use the shared format in [Errors](../errors.md). Base address: `https://api.infranest.io/api`.
## Maintenance windows
### List maintenance windows {#get-organizations-organization-maintenance-windows}
`GET` `/organizations/{organization}/maintenance-windows`
**Scope:** `monitoring.read` · **Changes data:** no
A paginated list of your maintenance windows with the monitors, servers and tags each window covers, whether each window is in effect and its current or next occurrence, plus counts in `meta`. Filter with `search`, `tag` and `status` (`active`, `scheduled`, `recurring` or `completed`), and sort with `sort` (`schedule`, `name`, `monitors` or `status`) and `dir`.
| Field | Type | Notes |
|---|---|---|
| `organization_id`
path · required | integer | Your organization's ID. |
**Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request**
```sh
curl "https://api.infranest.io/api/organizations/42/maintenance-windows" \
-H "Authorization: Bearer $INFRANEST_TOKEN" \
-H "Accept: application/json"
```
**Response** · 200
```json
{
"current_page": 1,
"data": [
{
"id": 3,
"organization_id": 1,
"name": "Nightly backup window",
"description": "Alerts are suppressed while backups run.",
"starts_at": null,
"ends_at": null,
"created_at": "2026-01-15T12:00:00.000000Z",
"updated_at": "2026-01-15T12:00:00.000000Z",
"recurrence_type": "daily",
"recurrence_days": null,
"start_time": "03:00",
"duration_minutes": 45,
"suppress_alerts": true,
"status": "scheduled",
"notified_at": null,
"source": "manual",
"deploy_id": null,
"deleted_at": null,
"purge_after": null,
"purge_reminder_sent_at": null,
"deleted_by_id": null,
"deleted_by_label": null,
"deletion_reason": null,
"created_by": null,
"checks_count": 0,
"checks": [],
"servers": [],
"tags": [],
"is_active": false,
"occurrence_starts_at": "2026-01-16T03:00:00Z",
"occurrence_ends_at": "2026-01-16T03:45:00Z",
"schedule_timezone": "UTC"
},
{
"id": 2,
"organization_id": 1,
"name": "Load balancer certificate rotation",
"description": "Replaced the certificate on web-lb and reloaded the listeners.",
"starts_at": "2026-01-06T01:00:00.000000Z",
"ends_at": "2026-01-06T01:30:00.000000Z",
"created_at": "2026-01-15T12:00:00.000000Z",
"updated_at": "2026-01-15T12:00:00.000000Z",
"recurrence_type": "none",
"recurrence_days": null,
"start_time": null,
"duration_minutes": null,
"suppress_alerts": true,
"status": "completed",
"notified_at": null,
"source": "manual",
"deploy_id": null,
"deleted_at": null,
"purge_after": null,
"purge_reminder_sent_at": null,
"deleted_by_id": null,
"deleted_by_label": null,
"deletion_reason": null,
"created_by": null,
"checks_count": 0,
"checks": [],
"servers": [],
"tags": [],
"is_active": false,
"occurrence_starts_at": null,
"occurrence_ends_at": null,
"schedule_timezone": "UTC"
}
],
"first_page_url": "http://localhost/api/organizations/1/maintenance-windows?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "http://localhost/api/organizations/1/maintenance-windows?page=1",
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "http://localhost/api/organizations/1/maintenance-windows?page=1",
"label": "1",
"page": 1,
"active": true
}
],
"next_page_url": null,
"path": "http://localhost/api/organizations/1/maintenance-windows",
"per_page": 25,
"prev_page_url": null,
"to": 3,
"total": 3,
"meta": {
"counts": {
"total": 3,
"active": 0,
"scheduled": 1,
"recurring": 1,
"completed": 1
},
"tags": []
}
}
```
---
### Create a maintenance window {#post-organizations-organization-maintenance-windows}
`POST` `/organizations/{organization}/maintenance-windows`
**Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization
Schedules maintenance for the monitors in `check_ids` and servers in `server_ids`; a window with no monitors applies to every monitor. A one-time window needs `starts_at` and `ends_at`, a `daily` or `weekly` one needs `start_time` and `duration_minutes`, and alerts are suppressed during it unless `suppress_alerts` is false. Subscribers of the affected status pages are told about the new window.
| Field | Type | Notes |
|---|---|---|
| `organization_id`
path · required | integer | Your organization's ID. |
| `name`
body · required | string | Must not be greater than 255 characters. |
| `description`
body | string, nullable | Must not be greater than 2000 characters. |
| `recurrence_type`
body | string, nullable | One of: `none`, `daily`, `weekly`. |
| `recurrence_days`
body | array | Must be at least 0. Must not be greater than 6. |
| `start_time`
body | string, nullable | Must be a valid date in the format H:i. |
| `duration_minutes`
body | integer, nullable | Must be at least 1. Must not be greater than 1440. |
| `starts_at`
body | string, nullable | Must be a valid date. |
| `ends_at`
body | string, nullable | Must be a valid date. Must be a date after starts_at. |
| `suppress_alerts`
body | boolean, nullable | |
| `check_ids`
body | array | Must match an existing stored value. |
| `server_ids`
body | array | Must match an existing stored value. |
**Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`idempotency_in_progress`](../errors.md#idempotency_in_progress), [`validation_failed`](../errors.md#validation_failed), [`idempotency_key_reused`](../errors.md#idempotency_key_reused), [`rate_limited`](../errors.md#rate_limited)
**Request**
```sh
curl -X POST "https://api.infranest.io/api/organizations/42/maintenance-windows" \
-H "Authorization: Bearer $INFRANEST_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name":"Load balancer upgrade","starts_at":"2026-01-17T22:00:00Z","ends_at":"2026-01-17T23:00:00Z","suppress_alerts":true,"check_ids":[1]}'
```
**Response** · 201 — Created
```json
{
"name": "Load balancer upgrade",
"description": null,
"recurrence_type": "none",
"recurrence_days": null,
"start_time": null,
"duration_minutes": null,
"starts_at": "2026-01-17T22:00:00.000000Z",
"ends_at": "2026-01-17T23:00:00.000000Z",
"suppress_alerts": true,
"organization_id": 1,
"updated_at": "2026-01-15T12:00:00.000000Z",
"created_at": "2026-01-15T12:00:00.000000Z",
"id": 6,
"checks": [
{
"id": 1,
"name": "Marketing site",
"type": "http",
"interval_minutes": 0,
"pivot": {
"maintenance_window_id": 6,
"monitoring_check_id": 1
}
}
],
"servers": [],
"tags": [],
"is_active": false,
"occurrence_starts_at": "2026-01-17T22:00:00Z",
"occurrence_ends_at": "2026-01-17T23:00:00Z",
"schedule_timezone": "UTC"
}
```
---
### Update a maintenance window {#patch-organizations-organization-maintenance-windows-maintenancewindow}
`PATCH` `/organizations/{organization}/maintenance-windows/{maintenanceWindow}`
**Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization
Changes the fields you send. Sending `check_ids` or `server_ids` replaces what the window covers, and an empty list clears it.
| Field | Type | Notes |
|---|---|---|
| `organization_id`
path · required | integer | Your organization's ID. |
| `maintenanceWindow_id`
path · required | integer | The maintenanceWindow's ID. |
| `name`
body | string | Must not be greater than 255 characters. |
| `description`
body | string, nullable | Must not be greater than 2000 characters. |
| `recurrence_type`
body | string, nullable | One of: `none`, `daily`, `weekly`. |
| `recurrence_days`
body | array | Must be at least 0. Must not be greater than 6. |
| `start_time`
body | string, nullable | Must be a valid date in the format H:i. |
| `duration_minutes`
body | integer, nullable | Must be at least 1. Must not be greater than 1440. |
| `starts_at`
body | string, nullable | Must be a valid date. |
| `ends_at`
body | string, nullable | Must be a valid date. Must be a date after starts_at. |
| `suppress_alerts`
body | boolean, nullable | |
| `check_ids`
body | array | Must match an existing stored value. |
| `server_ids`
body | array | Must match an existing stored value. |
**Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`validation_failed`](../errors.md#validation_failed), [`rate_limited`](../errors.md#rate_limited)
**Request**
```sh
curl -X PATCH "https://api.infranest.io/api/organizations/42/maintenance-windows/1" \
-H "Authorization: Bearer $INFRANEST_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"description":"Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode."}'
```
**Response** · 200
```json
{
"id": 1,
"organization_id": 1,
"name": "Database cluster upgrade",
"description": "Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode.",
"starts_at": "2026-01-18T02:00:00.000000Z",
"ends_at": "2026-01-18T03:00:00.000000Z",
"created_at": "2026-01-15T12:00:00.000000Z",
"updated_at": "2026-01-15T12:00:00.000000Z",
"recurrence_type": "none",
"recurrence_days": null,
"start_time": null,
"duration_minutes": null,
"suppress_alerts": true,
"status": "scheduled",
"notified_at": null,
"source": "manual",
"deploy_id": null,
"deleted_at": null,
"purge_after": null,
"purge_reminder_sent_at": null,
"deleted_by_id": null,
"deleted_by_label": null,
"deletion_reason": null,
"created_by": null,
"checks": [],
"servers": [],
"tags": [],
"is_active": false,
"occurrence_starts_at": "2026-01-18T02:00:00Z",
"occurrence_ends_at": "2026-01-18T03:00:00Z",
"schedule_timezone": "UTC"
}
```
---
### Delete a maintenance window {#delete-organizations-organization-maintenance-windows-maintenancewindow}
`DELETE` `/organizations/{organization}/maintenance-windows/{maintenanceWindow}`
**Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization
Permanently deletes the maintenance window.
| Field | Type | Notes |
|---|---|---|
| `organization_id`
path · required | integer | Your organization's ID. |
| `maintenanceWindow_id`
path · required | integer | The maintenanceWindow's ID. |
**Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request**
```sh
curl -X DELETE "https://api.infranest.io/api/organizations/42/maintenance-windows/1" \
-H "Authorization: Bearer $INFRANEST_TOKEN" \
-H "Accept: application/json"
```
**Response** · 200
```json
{
"message": "Deleted."
}
```
---
### Complete a maintenance window {#patch-organizations-organization-maintenance-windows-maintenancewindow-complete}
`PATCH` `/organizations/{organization}/maintenance-windows/{maintenanceWindow}/complete`
**Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization
Marks a window that is in progress or verifying as completed. Refused for a window in any other state.
| Field | Type | Notes |
|---|---|---|
| `organization_id`
path · required | integer | Your organization's ID. |
| `maintenanceWindow_id`
path · required | integer | The maintenanceWindow's ID. |
**Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`validation_failed`](../errors.md#validation_failed), [`rate_limited`](../errors.md#rate_limited)
**Request**
```sh
curl -X PATCH "https://api.infranest.io/api/organizations/42/maintenance-windows/1/complete" \
-H "Authorization: Bearer $INFRANEST_TOKEN" \
-H "Accept: application/json"
```
**Response** · 200
```json
{
"id": 4,
"organization_id": 1,
"name": "Database upgrade",
"description": null,
"starts_at": "2026-01-15T11:50:00.000000Z",
"ends_at": "2026-01-15T13:00:00.000000Z",
"created_at": "2026-01-15T12:00:00.000000Z",
"updated_at": "2026-01-15T12:00:00.000000Z",
"recurrence_type": "none",
"recurrence_days": null,
"start_time": null,
"duration_minutes": null,
"suppress_alerts": true,
"status": "completed",
"notified_at": null,
"source": "manual",
"deploy_id": null,
"deleted_at": null,
"purge_after": null,
"purge_reminder_sent_at": null,
"deleted_by_id": null,
"deleted_by_label": null,
"deletion_reason": null,
"created_by": null,
"checks": [],
"servers": [],
"tags": [],
"is_active": false,
"occurrence_starts_at": null,
"occurrence_ends_at": null,
"schedule_timezone": "UTC"
}
```
---
### Mark a maintenance window as verifying {#patch-organizations-organization-maintenance-windows-maintenancewindow-verifying}
`PATCH` `/organizations/{organization}/maintenance-windows/{maintenanceWindow}/verifying`
**Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization
Moves a window that is in progress to `verifying`, while you check that everything works again. Refused for a window in any other state.
| Field | Type | Notes |
|---|---|---|
| `organization_id`
path · required | integer | Your organization's ID. |
| `maintenanceWindow_id`
path · required | integer | The maintenanceWindow's ID. |
**Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`validation_failed`](../errors.md#validation_failed), [`rate_limited`](../errors.md#rate_limited)
**Request**
```sh
curl -X PATCH "https://api.infranest.io/api/organizations/42/maintenance-windows/1/verifying" \
-H "Authorization: Bearer $INFRANEST_TOKEN" \
-H "Accept: application/json"
```
**Response** · 200
```json
{
"id": 4,
"organization_id": 1,
"name": "Database upgrade",
"description": null,
"starts_at": "2026-01-15T11:50:00.000000Z",
"ends_at": "2026-01-15T13:00:00.000000Z",
"created_at": "2026-01-15T12:00:00.000000Z",
"updated_at": "2026-01-15T12:00:00.000000Z",
"recurrence_type": "none",
"recurrence_days": null,
"start_time": null,
"duration_minutes": null,
"suppress_alerts": true,
"status": "verifying",
"notified_at": null,
"source": "manual",
"deploy_id": null,
"deleted_at": null,
"purge_after": null,
"purge_reminder_sent_at": null,
"deleted_by_id": null,
"deleted_by_label": null,
"deletion_reason": null,
"created_by": null,
"checks": [],
"servers": [],
"tags": [],
"is_active": true,
"occurrence_starts_at": "2026-01-15T11:50:00Z",
"occurrence_ends_at": "2026-01-15T13:00:00Z",
"schedule_timezone": "UTC"
}
```