Skip to content

Maintenance ​

Planned maintenance windows, which pause alerts and show on status pages.

Common tasks

Only in the app: Nothing. Maintenance windows can be fully managed with a token.

How it works in the app: help article.

Scopes: Read with monitoring.read, change with monitoring.write. See Tokens and scopes.

Every endpoint below takes a token in the Authorization: Bearer header and answers JSON. Errors use the shared format in Errors. Base address: https://api.infranest.io/api.

Maintenance windows ​

List maintenance windows ​

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.

GET/organizations/{organization}/maintenance-windows
Scope monitoring.readRead only
Authorizationheader
Authorizationstringrequired

Bearer and your API token: Bearer $INFRANEST_TOKEN. See Tokens and scopes.

Path parameters
organizationintegerrequired

Your organization's ID: the number after /organizations/ in the app's address, or from GET /organizations.

Request

sh
curl "https://api.infranest.io/api/organizations/42/maintenance-windows" \
  -H "Authorization: Bearer $INFRANEST_TOKEN" \
  -H "Accept: application/json"
powershell
$headers = @{
  Authorization = "Bearer $env:INFRANEST_TOKEN"
  Accept = "application/json"
}
Invoke-RestMethod -Method Get -Uri "https://api.infranest.io/api/organizations/42/maintenance-windows" -Headers $headers
php
<?php
// composer require guzzlehttp/guzzle
require "vendor/autoload.php";

$client = new GuzzleHttp\Client();
$response = $client->request('GET', 'https://api.infranest.io/api/organizations/42/maintenance-windows', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('INFRANEST_TOKEN'),
        'Accept' => 'application/json',
    ],
]);

echo $response->getBody();
python
import os

import requests

response = requests.get(
    "https://api.infranest.io/api/organizations/42/maintenance-windows",
    headers={
        "Authorization": f"Bearer {os.environ['INFRANEST_TOKEN']}",
        "Accept": "application/json",
    },
)
response.raise_for_status()
print(response.json())
js
const response = await fetch('https://api.infranest.io/api/organizations/42/maintenance-windows', {
  headers: {
    Authorization: `Bearer ${process.env.INFRANEST_TOKEN}`,
    Accept: 'application/json',
  },
})
console.log(response.status, await response.text())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.infranest.io/api/organizations/42/maintenance-windows", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRANEST_TOKEN"))
	req.Header.Set("Accept", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}

Response

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": "&laquo; 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": []
  }
}
json
{
  "code": "unauthenticated",
  "message": "You are not signed in, or the API token is missing, wrong, expired or revoked.",
  "hint": "Send a valid token in the Authorization header, as the word Bearer followed by the token. Create a new one under My account → Developer if it expired or was revoked.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#unauthenticated",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "scope_missing",
  "message": "This API token does not have the monitoring.read scope.",
  "hint": "Create a token that includes the scope named in \"required\". Give each token only the scopes it needs.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#scope_missing",
  "required": "monitoring.read",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "not_found",
  "message": "Nothing exists at this address, or you cannot see it.",
  "hint": "Check the IDs in the address. A resource in another organization answers as not found.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#not_found",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "rate_limited",
  "message": "This token made more than 300 requests in a minute.",
  "hint": "Wait the number of seconds in \"retry_after\" (also the Retry-After header), then retry.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#rate_limited",
  "limit_key": "api_requests_per_minute",
  "limit": 300,
  "retry_after": 12,
  "reference": "k3j9x0b2qa"
}

401 unauthenticated
403 scope_missing wrong_organization test_token_required test_token_sandbox_only permission_denied
404 not_found
429 rate_limited


Create a maintenance window ​

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.

POST/organizations/{organization}/maintenance-windows
Scope monitoring.writeChanges data
Authorizationheader
Authorizationstringrequired

Bearer and your API token: Bearer $INFRANEST_TOKEN. See Tokens and scopes.

Path parameters
organizationintegerrequired

Your organization's ID: the number after /organizations/ in the app's address, or from GET /organizations.

Bodyapplication/json
namestringrequired

Must not be greater than 255 characters.

descriptionstring, nullableoptional

Must not be greater than 2000 characters.

recurrence_typestring, nullableoptional

One of: none, daily, weekly

recurrence_daysarrayoptional

Must be at least 0. Must not be greater than 6.

start_timestring, nullableoptional

Must be a valid date in the format H:i.

duration_minutesinteger, nullableoptional

Must be at least 1. Must not be greater than 1440.

starts_atstring, nullableoptional

Must be a valid date.

ends_atstring, nullableoptional

Must be a valid date. Must be a date after starts_at.

suppress_alertsboolean, nullableoptional
check_idsarrayoptional

Must match an existing stored value.

server_idsarrayoptional

Must match an existing stored value.

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]}'
powershell
$headers = @{
  Authorization = "Bearer $env:INFRANEST_TOKEN"
  Accept = "application/json"
}
$body = @'
{
  "name": "Load balancer upgrade",
  "starts_at": "2026-01-17T22:00:00Z",
  "ends_at": "2026-01-17T23:00:00Z",
  "suppress_alerts": true,
  "check_ids": [
    1
  ]
}
'@
Invoke-RestMethod -Method Post -Uri "https://api.infranest.io/api/organizations/42/maintenance-windows" -Headers $headers -ContentType "application/json" -Body $body
php
<?php
// composer require guzzlehttp/guzzle
require "vendor/autoload.php";

$client = new GuzzleHttp\Client();
$response = $client->request('POST', 'https://api.infranest.io/api/organizations/42/maintenance-windows', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('INFRANEST_TOKEN'),
        'Accept' => 'application/json',
    ],
    'json' => [
        'name' => 'Load balancer upgrade',
        'starts_at' => '2026-01-17T22:00:00Z',
        'ends_at' => '2026-01-17T23:00:00Z',
        'suppress_alerts' => true,
        'check_ids' => [
            1,
        ],
    ],
]);

echo $response->getBody();
python
import os

import requests

response = requests.post(
    "https://api.infranest.io/api/organizations/42/maintenance-windows",
    headers={
        "Authorization": f"Bearer {os.environ['INFRANEST_TOKEN']}",
        "Accept": "application/json",
    },
    json={
        "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.raise_for_status()
print(response.json())
js
const response = await fetch('https://api.infranest.io/api/organizations/42/maintenance-windows', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.INFRANEST_TOKEN}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Load balancer upgrade",
    "starts_at": "2026-01-17T22:00:00Z",
    "ends_at": "2026-01-17T23:00:00Z",
    "suppress_alerts": true,
    "check_ids": [
      1
    ]
  }),
})
console.log(response.status, await response.text())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	req, err := http.NewRequest("POST", "https://api.infranest.io/api/organizations/42/maintenance-windows", strings.NewReader(`{"name":"Load balancer upgrade","starts_at":"2026-01-17T22:00:00Z","ends_at":"2026-01-17T23:00:00Z","suppress_alerts":true,"check_ids":[1]}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRANEST_TOKEN"))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}

Response

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"
}
json
{
  "code": "unauthenticated",
  "message": "You are not signed in, or the API token is missing, wrong, expired or revoked.",
  "hint": "Send a valid token in the Authorization header, as the word Bearer followed by the token. Create a new one under My account → Developer if it expired or was revoked.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#unauthenticated",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "scope_missing",
  "message": "This API token does not have the monitoring.write scope.",
  "hint": "Create a token that includes the scope named in \"required\". Give each token only the scopes it needs.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#scope_missing",
  "required": "monitoring.write",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "not_found",
  "message": "Nothing exists at this address, or you cannot see it.",
  "hint": "Check the IDs in the address. A resource in another organization answers as not found.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#not_found",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "idempotency_in_progress",
  "message": "A request with this Idempotency-Key is still being handled.",
  "hint": "Wait a few seconds, then send the same request with the same key again to get its result.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#idempotency_in_progress",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "validation_failed",
  "message": "The name field is required.",
  "hint": "Fix the fields listed in \"errors\" and send the request again.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#validation_failed",
  "errors": {
    "name": [
      "The name field is required."
    ]
  },
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "rate_limited",
  "message": "This token made more than 300 requests in a minute.",
  "hint": "Wait the number of seconds in \"retry_after\" (also the Retry-After header), then retry.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#rate_limited",
  "limit_key": "api_requests_per_minute",
  "limit": 300,
  "retry_after": 12,
  "reference": "k3j9x0b2qa"
}

401 unauthenticated
403 scope_missing wrong_organization test_token_required test_token_sandbox_only permission_denied write_disabled organization_suspended
404 not_found
409 idempotency_in_progress
422 validation_failed idempotency_key_reused
429 rate_limited


Update a maintenance window ​

Changes the fields you send. Sending check_ids or server_ids replaces what the window covers, and an empty list clears it.

PATCH/organizations/{organization}/maintenance-windows/{maintenanceWindow}
Scope monitoring.writeChanges data
Authorizationheader
Authorizationstringrequired

Bearer and your API token: Bearer $INFRANEST_TOKEN. See Tokens and scopes.

Path parameters
organizationintegerrequired

Your organization's ID: the number after /organizations/ in the app's address, or from GET /organizations.

maintenanceWindowintegerrequired

The maintenance window's ID.

Bodyapplication/json
namestringoptional

Must not be greater than 255 characters.

descriptionstring, nullableoptional

Must not be greater than 2000 characters.

recurrence_typestring, nullableoptional

One of: none, daily, weekly

recurrence_daysarrayoptional

Must be at least 0. Must not be greater than 6.

start_timestring, nullableoptional

Must be a valid date in the format H:i.

duration_minutesinteger, nullableoptional

Must be at least 1. Must not be greater than 1440.

starts_atstring, nullableoptional

Must be a valid date.

ends_atstring, nullableoptional

Must be a valid date. Must be a date after starts_at.

suppress_alertsboolean, nullableoptional
check_idsarrayoptional

Must match an existing stored value.

server_idsarrayoptional

Must match an existing stored value.

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."}'
powershell
$headers = @{
  Authorization = "Bearer $env:INFRANEST_TOKEN"
  Accept = "application/json"
}
$body = @'
{
  "description": "Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode."
}
'@
Invoke-RestMethod -Method Patch -Uri "https://api.infranest.io/api/organizations/42/maintenance-windows/1" -Headers $headers -ContentType "application/json" -Body $body
php
<?php
// composer require guzzlehttp/guzzle
require "vendor/autoload.php";

$client = new GuzzleHttp\Client();
$response = $client->request('PATCH', 'https://api.infranest.io/api/organizations/42/maintenance-windows/1', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('INFRANEST_TOKEN'),
        'Accept' => 'application/json',
    ],
    'json' => [
        'description' => 'Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode.',
    ],
]);

echo $response->getBody();
python
import os

import requests

response = requests.patch(
    "https://api.infranest.io/api/organizations/42/maintenance-windows/1",
    headers={
        "Authorization": f"Bearer {os.environ['INFRANEST_TOKEN']}",
        "Accept": "application/json",
    },
    json={
        "description": "Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode.",
    },
)
response.raise_for_status()
print(response.json())
js
const response = await fetch('https://api.infranest.io/api/organizations/42/maintenance-windows/1', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.INFRANEST_TOKEN}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "description": "Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode."
  }),
})
console.log(response.status, await response.text())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.infranest.io/api/organizations/42/maintenance-windows/1", strings.NewReader(`{"description":"Primary database moves to PostgreSQL 17. Expect two minutes of read-only mode."}`))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRANEST_TOKEN"))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}

Response

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"
}
json
{
  "code": "unauthenticated",
  "message": "You are not signed in, or the API token is missing, wrong, expired or revoked.",
  "hint": "Send a valid token in the Authorization header, as the word Bearer followed by the token. Create a new one under My account → Developer if it expired or was revoked.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#unauthenticated",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "scope_missing",
  "message": "This API token does not have the monitoring.write scope.",
  "hint": "Create a token that includes the scope named in \"required\". Give each token only the scopes it needs.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#scope_missing",
  "required": "monitoring.write",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "not_found",
  "message": "Nothing exists at this address, or you cannot see it.",
  "hint": "Check the IDs in the address. A resource in another organization answers as not found.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#not_found",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "validation_failed",
  "message": "The name field is required.",
  "hint": "Fix the fields listed in \"errors\" and send the request again.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#validation_failed",
  "errors": {
    "name": [
      "The name field is required."
    ]
  },
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "rate_limited",
  "message": "This token made more than 300 requests in a minute.",
  "hint": "Wait the number of seconds in \"retry_after\" (also the Retry-After header), then retry.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#rate_limited",
  "limit_key": "api_requests_per_minute",
  "limit": 300,
  "retry_after": 12,
  "reference": "k3j9x0b2qa"
}

401 unauthenticated
403 scope_missing wrong_organization test_token_required test_token_sandbox_only permission_denied write_disabled organization_suspended
404 not_found
422 validation_failed
429 rate_limited


Delete a maintenance window ​

Permanently deletes the maintenance window.

DELETE/organizations/{organization}/maintenance-windows/{maintenanceWindow}
Scope monitoring.writeChanges data
Authorizationheader
Authorizationstringrequired

Bearer and your API token: Bearer $INFRANEST_TOKEN. See Tokens and scopes.

Path parameters
organizationintegerrequired

Your organization's ID: the number after /organizations/ in the app's address, or from GET /organizations.

maintenanceWindowintegerrequired

The maintenance window's ID.

Request

sh
curl -X DELETE "https://api.infranest.io/api/organizations/42/maintenance-windows/1" \
  -H "Authorization: Bearer $INFRANEST_TOKEN" \
  -H "Accept: application/json"
powershell
$headers = @{
  Authorization = "Bearer $env:INFRANEST_TOKEN"
  Accept = "application/json"
}
Invoke-RestMethod -Method Delete -Uri "https://api.infranest.io/api/organizations/42/maintenance-windows/1" -Headers $headers
php
<?php
// composer require guzzlehttp/guzzle
require "vendor/autoload.php";

$client = new GuzzleHttp\Client();
$response = $client->request('DELETE', 'https://api.infranest.io/api/organizations/42/maintenance-windows/1', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('INFRANEST_TOKEN'),
        'Accept' => 'application/json',
    ],
]);

echo $response->getBody();
python
import os

import requests

response = requests.delete(
    "https://api.infranest.io/api/organizations/42/maintenance-windows/1",
    headers={
        "Authorization": f"Bearer {os.environ['INFRANEST_TOKEN']}",
        "Accept": "application/json",
    },
)
response.raise_for_status()
print(response.status_code)
js
const response = await fetch('https://api.infranest.io/api/organizations/42/maintenance-windows/1', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.INFRANEST_TOKEN}`,
    Accept: 'application/json',
  },
})
console.log(response.status, await response.text())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("DELETE", "https://api.infranest.io/api/organizations/42/maintenance-windows/1", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRANEST_TOKEN"))
	req.Header.Set("Accept", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}

Response

json
{
  "message": "Deleted."
}
json
{
  "code": "unauthenticated",
  "message": "You are not signed in, or the API token is missing, wrong, expired or revoked.",
  "hint": "Send a valid token in the Authorization header, as the word Bearer followed by the token. Create a new one under My account → Developer if it expired or was revoked.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#unauthenticated",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "scope_missing",
  "message": "This API token does not have the monitoring.write scope.",
  "hint": "Create a token that includes the scope named in \"required\". Give each token only the scopes it needs.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#scope_missing",
  "required": "monitoring.write",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "not_found",
  "message": "Nothing exists at this address, or you cannot see it.",
  "hint": "Check the IDs in the address. A resource in another organization answers as not found.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#not_found",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "rate_limited",
  "message": "This token made more than 300 requests in a minute.",
  "hint": "Wait the number of seconds in \"retry_after\" (also the Retry-After header), then retry.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#rate_limited",
  "limit_key": "api_requests_per_minute",
  "limit": 300,
  "retry_after": 12,
  "reference": "k3j9x0b2qa"
}

401 unauthenticated
403 scope_missing wrong_organization test_token_required test_token_sandbox_only permission_denied write_disabled organization_suspended
404 not_found
429 rate_limited


Complete a maintenance window ​

Marks a window that is in progress or verifying as completed. Refused for a window in any other state.

PATCH/organizations/{organization}/maintenance-windows/{maintenanceWindow}/complete
Scope monitoring.writeChanges data
Authorizationheader
Authorizationstringrequired

Bearer and your API token: Bearer $INFRANEST_TOKEN. See Tokens and scopes.

Path parameters
organizationintegerrequired

Your organization's ID: the number after /organizations/ in the app's address, or from GET /organizations.

maintenanceWindowintegerrequired

The maintenance window's ID.

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"
powershell
$headers = @{
  Authorization = "Bearer $env:INFRANEST_TOKEN"
  Accept = "application/json"
}
Invoke-RestMethod -Method Patch -Uri "https://api.infranest.io/api/organizations/42/maintenance-windows/1/complete" -Headers $headers
php
<?php
// composer require guzzlehttp/guzzle
require "vendor/autoload.php";

$client = new GuzzleHttp\Client();
$response = $client->request('PATCH', 'https://api.infranest.io/api/organizations/42/maintenance-windows/1/complete', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('INFRANEST_TOKEN'),
        'Accept' => 'application/json',
    ],
]);

echo $response->getBody();
python
import os

import requests

response = requests.patch(
    "https://api.infranest.io/api/organizations/42/maintenance-windows/1/complete",
    headers={
        "Authorization": f"Bearer {os.environ['INFRANEST_TOKEN']}",
        "Accept": "application/json",
    },
)
response.raise_for_status()
print(response.json())
js
const response = await fetch('https://api.infranest.io/api/organizations/42/maintenance-windows/1/complete', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.INFRANEST_TOKEN}`,
    Accept: 'application/json',
  },
})
console.log(response.status, await response.text())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.infranest.io/api/organizations/42/maintenance-windows/1/complete", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRANEST_TOKEN"))
	req.Header.Set("Accept", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}

Response

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"
}
json
{
  "code": "unauthenticated",
  "message": "You are not signed in, or the API token is missing, wrong, expired or revoked.",
  "hint": "Send a valid token in the Authorization header, as the word Bearer followed by the token. Create a new one under My account → Developer if it expired or was revoked.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#unauthenticated",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "scope_missing",
  "message": "This API token does not have the monitoring.write scope.",
  "hint": "Create a token that includes the scope named in \"required\". Give each token only the scopes it needs.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#scope_missing",
  "required": "monitoring.write",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "not_found",
  "message": "Nothing exists at this address, or you cannot see it.",
  "hint": "Check the IDs in the address. A resource in another organization answers as not found.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#not_found",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "validation_failed",
  "message": "The name field is required.",
  "hint": "Fix the fields listed in \"errors\" and send the request again.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#validation_failed",
  "errors": {
    "name": [
      "The name field is required."
    ]
  },
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "rate_limited",
  "message": "This token made more than 300 requests in a minute.",
  "hint": "Wait the number of seconds in \"retry_after\" (also the Retry-After header), then retry.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#rate_limited",
  "limit_key": "api_requests_per_minute",
  "limit": 300,
  "retry_after": 12,
  "reference": "k3j9x0b2qa"
}

401 unauthenticated
403 scope_missing wrong_organization test_token_required test_token_sandbox_only permission_denied write_disabled organization_suspended
404 not_found
422 validation_failed
429 rate_limited


Mark a maintenance window as verifying ​

Moves a window that is in progress to verifying, while you check that everything works again. Refused for a window in any other state.

PATCH/organizations/{organization}/maintenance-windows/{maintenanceWindow}/verifying
Scope monitoring.writeChanges data
Authorizationheader
Authorizationstringrequired

Bearer and your API token: Bearer $INFRANEST_TOKEN. See Tokens and scopes.

Path parameters
organizationintegerrequired

Your organization's ID: the number after /organizations/ in the app's address, or from GET /organizations.

maintenanceWindowintegerrequired

The maintenance window's ID.

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"
powershell
$headers = @{
  Authorization = "Bearer $env:INFRANEST_TOKEN"
  Accept = "application/json"
}
Invoke-RestMethod -Method Patch -Uri "https://api.infranest.io/api/organizations/42/maintenance-windows/1/verifying" -Headers $headers
php
<?php
// composer require guzzlehttp/guzzle
require "vendor/autoload.php";

$client = new GuzzleHttp\Client();
$response = $client->request('PATCH', 'https://api.infranest.io/api/organizations/42/maintenance-windows/1/verifying', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('INFRANEST_TOKEN'),
        'Accept' => 'application/json',
    ],
]);

echo $response->getBody();
python
import os

import requests

response = requests.patch(
    "https://api.infranest.io/api/organizations/42/maintenance-windows/1/verifying",
    headers={
        "Authorization": f"Bearer {os.environ['INFRANEST_TOKEN']}",
        "Accept": "application/json",
    },
)
response.raise_for_status()
print(response.json())
js
const response = await fetch('https://api.infranest.io/api/organizations/42/maintenance-windows/1/verifying', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.INFRANEST_TOKEN}`,
    Accept: 'application/json',
  },
})
console.log(response.status, await response.text())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("PATCH", "https://api.infranest.io/api/organizations/42/maintenance-windows/1/verifying", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRANEST_TOKEN"))
	req.Header.Set("Accept", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}

Response

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"
}
json
{
  "code": "unauthenticated",
  "message": "You are not signed in, or the API token is missing, wrong, expired or revoked.",
  "hint": "Send a valid token in the Authorization header, as the word Bearer followed by the token. Create a new one under My account → Developer if it expired or was revoked.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#unauthenticated",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "scope_missing",
  "message": "This API token does not have the monitoring.write scope.",
  "hint": "Create a token that includes the scope named in \"required\". Give each token only the scopes it needs.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#scope_missing",
  "required": "monitoring.write",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "not_found",
  "message": "Nothing exists at this address, or you cannot see it.",
  "hint": "Check the IDs in the address. A resource in another organization answers as not found.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#not_found",
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "validation_failed",
  "message": "The name field is required.",
  "hint": "Fix the fields listed in \"errors\" and send the request again.",
  "retryable": false,
  "docs_url": "https://developers.infranest.io/errors#validation_failed",
  "errors": {
    "name": [
      "The name field is required."
    ]
  },
  "reference": "k3j9x0b2qa"
}
json
{
  "code": "rate_limited",
  "message": "This token made more than 300 requests in a minute.",
  "hint": "Wait the number of seconds in \"retry_after\" (also the Retry-After header), then retry.",
  "retryable": true,
  "docs_url": "https://developers.infranest.io/errors#rate_limited",
  "limit_key": "api_requests_per_minute",
  "limit": 300,
  "retry_after": 12,
  "reference": "k3j9x0b2qa"
}

401 unauthenticated
403 scope_missing wrong_organization test_token_required test_token_sandbox_only permission_denied write_disabled organization_suspended
404 not_found
422 validation_failed
429 rate_limited