HeimPulse API

Maintenance Windows

The real request/response field shape for POST /v1/maintenance-windows and its /updates route.

View as Markdown

/v1/maintenance-windows is a thin proxy in front of the same engine that powers the dashboard’s maintenance tab - so its request/response bodies are plain JSON objects, not one of the reference’s typed schemas (see the API reference for why those two endpoints show up there as a bare object). This page is the field-by-field shape. For the incident counterpart, see the Incidents guide - the two are separate endpoints, not variants of each other.

Schedule a maintenance window

POST /v1/maintenance-windows
{
  "title": "Database upgrade",
  "service_ids": ["5b1e...", "8a2f..."],
  "message": "Upgrading the primary database. Expect brief connection drops.",
  "scheduled_start": "2026-09-10T02:00:00Z",
  "scheduled_end": "2026-09-10T03:00:00Z"
}
Field Type Required Notes
title string yes Non-empty.
service_ids array of uuid yes Non-empty; every id must belong to your org.
message string yes The maintenance window’s first update.
scheduled_start string (RFC 3339) yes When the window begins.
scheduled_end string (RFC 3339) yes Must be after scheduled_start.

kind is not a field you send - every maintenance window created through this endpoint is forced to kind maintenance server-side, even if you send something else. severity is never accepted here either - maintenance windows don’t carry one; sending it is rejected as invalid.

A 201 response is the full maintenance window, including its initial update:

{
  "id": "c4e1...",
  "kind": "maintenance",
  "title": "Database upgrade",
  "status": "scheduled",
  "severity": null,
  "created_by": null,
  "created_at": "2026-09-05T12:00:00Z",
  "resolved_at": null,
  "scheduled_start": "2026-09-10T02:00:00Z",
  "scheduled_end": "2026-09-10T03:00:00Z",
  "service_ids": ["5b1e...", "8a2f..."],
  "display_id": "MNT-7",
  "updated_at": "2026-09-05T12:00:00Z",
  "auto_managed": false,
  "updates": [
    { "id": "...", "body": "Upgrading the primary database...", "status_at_update": "scheduled", "created_at": "..." }
  ]
}

created_by is always null for a maintenance window created through the API - there’s no human session behind an API key, so it’s attributed to the system.

Post an update (including completing it)

POST /v1/maintenance-windows/{id}/updates
{ "body": "Upgrade underway.", "status": "in_progress" }
Field Type Required Notes
body string yes Non-empty.
status string yes One of scheduled, in_progress, completed.

There’s no separate “complete” endpoint. Completing a maintenance window is posting an update with "status": "completed" - that’s the one status this API treats as terminal (it sets resolved_at and stops counting the window as active).

{ "body": "Upgrade complete, all services back to normal.", "status": "completed" }

Listing and reading

GET /v1/maintenance-windows?section=active
GET /v1/maintenance-windows/{id}

section is required on the list endpoint: active or resolved (a completed window counts as resolved). Optional filters: q (searches title and display id, e.g. MNT-7), one or more service_id params, and page/limit for pagination. There’s no severity filter - maintenance windows don’t have one.