Deployments & Maintenance
Announce deploys and maintenance windows from your own CI so Ionhour pauses probing or suppresses alerts while you work.
Two related endpoints let you tell Ionhour "we're changing something right now" from a customer's own pipeline. They behave differently, and the difference matters:
| Deployment | Maintenance window | |
|---|---|---|
| Effect | Auto-pauses the associated checks | Suppresses alerts and incidents |
| Probing | Stops (paused checks are not probed) | Continues (data keeps flowing) |
| Use when | A release restarts or briefly breaks a service | Planned work where you still want data but no noise |
| Resource | mcp:deployments | mcp:maintenance_windows |
Both are workspace-scoped and self-healing: each has a TTL so an orphaned window (a pipeline that crashed before closing it) cleans itself up. All routes are under https://api.ionhour.com/api/v1.
Deployments
| Method | Path | Min role | Purpose |
|---|---|---|---|
POST | /v1/deployments | member | Open a deployment window (pauses checks). |
POST | /v1/deployments/:id/end | member | Close it (resumes paused checks). |
GET | /v1/deployments | viewer | List deployments. |
Open a deployment
POST /v1/deployments
| Field | Type | Required | Notes |
|---|---|---|---|
projectId | number | Yes | The project being deployed. Must belong to the key's workspace. |
name | string | No | Human label (max 255). |
version | string | No | Release/version string (max 255). |
author | string | No | Who triggered it (max 255). |
link | string | No | URL back to the CI run (max 2048). |
checkIds | number[] | No | Specific checks to pause. Omitted → all checks in the project. |
autoPause | boolean | No | Pause the checks for the window. Defaults to true. |
ttlMinutes | number | No | Server-side auto-end, 1–1440 minutes from now. A fail-safe if /end never fires. |
ttlMinutes is a safety net, not a schedule. The auto-end cron runs on a few-minute cadence, so a window ends around its TTL, not to the second. The explicit /end call is the precise close. Always send /end, and set a TTL so a failed pipeline still recovers.
curl -X POST https://api.ionhour.com/api/v1/deployments \
-H "Authorization: Bearer ionh_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"projectId": 7,
"version": "v1.4.2",
"author": "ci-bot",
"link": "https://github.com/acme/app/actions/runs/123",
"autoPause": true,
"ttlMinutes": 45
}'The response includes the deployment id, status (SCHEDULED, ACTIVE, or ENDED), and scheduledEndAt (set when you pass a TTL):
{
"id": 910,
"projectId": 7,
"name": null,
"version": "v1.4.2",
"author": "ci-bot",
"link": "https://github.com/acme/app/actions/runs/123",
"status": "ACTIVE",
"autoPause": true,
"checkIds": null,
"startedAt": "2026-07-10T14:00:00.000Z",
"endedAt": null,
"scheduledEndAt": "2026-07-10T14:45:00.000Z"
}End a deployment
POST /v1/deployments/:id/end resumes the auto-paused checks. It is idempotent — ending an already-ended deployment returns 200 with its current state.
curl -X POST https://api.ionhour.com/api/v1/deployments/910/end \
-H "Authorization: Bearer ionh_your_api_key"List deployments
GET /v1/deployments accepts projectId, status, from, to, page, and limit, and returns the standard paginated envelope.
Maintenance windows
| Method | Path | Min role | Purpose |
|---|---|---|---|
POST | /v1/maintenance-windows | member | Open a maintenance window (suppresses alerts/incidents). |
POST | /v1/maintenance-windows/:id/end | member | End it early. |
GET | /v1/maintenance-windows | viewer | List windows. |
Open a window
POST /v1/maintenance-windows
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | Window label (max 255). |
endAt | ISO-8601 | Yes | When the window ends — its natural TTL. A background processor auto-completes the window past endAt. |
description | string | No | Max 2000 chars. |
startAt | ISO-8601 | No | Defaults to now. |
projectIds | number[] | No | Projects covered. Omitted → all projects in the workspace. Every id must belong to the workspace. |
suppressAlerts | boolean | No | Defaults to true. |
suppressIncidents | boolean | No | Defaults to true. |
curl -X POST https://api.ionhour.com/api/v1/maintenance-windows \
-H "Authorization: Bearer ionh_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "DB migration",
"endAt": "2026-07-10T15:00:00.000Z",
"projectIds": [7],
"suppressAlerts": true,
"suppressIncidents": true
}'The response includes the window id, state (SCHEDULED, ACTIVE, COMPLETED, or CANCELLED), and the resolved projectIds.
End a window
POST /v1/maintenance-windows/:id/end ends the window early (→ COMPLETED). Like deployments, it is idempotent — ending a window that is already in a terminal state returns its current state.
Because endAt is a TTL, a window closes on its own even if this call never fires — the natural self-healing path for a crashed pipeline.
List windows
GET /v1/maintenance-windows accepts state, projectId, from, to, page, and limit, and returns the standard paginated envelope.
Example: wrap a deploy in GitHub Actions
This generic workflow opens a deployment window before the release and closes it afterward. The close step uses if: always() so it runs even when the deploy fails, and the ttlMinutes / endAt TTLs guarantee cleanup even if the whole runner dies. Store your key as the IONHOUR_API_KEY secret.
name: deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
env:
IONHOUR_API_KEY: ${{ secrets.IONHOUR_API_KEY }}
IONHOUR_BASE: https://api.ionhour.com/api/v1
IONHOUR_PROJECT_ID: '7'
steps:
- name: Open Ionhour deployment window
id: ionhour_open
run: |
DEPLOY_ID=$(curl -sS -X POST "$IONHOUR_BASE/deployments" \
-H "Authorization: Bearer $IONHOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"projectId\": $IONHOUR_PROJECT_ID,
\"version\": \"${GITHUB_SHA::7}\",
\"author\": \"$GITHUB_ACTOR\",
\"link\": \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",
\"autoPause\": true,
\"ttlMinutes\": 45
}" | jq -r '.id')
echo "deploy_id=$DEPLOY_ID" >> "$GITHUB_OUTPUT"
- name: Deploy
run: ./scripts/deploy.sh
- name: Close Ionhour deployment window
if: always() && steps.ionhour_open.outputs.deploy_id != ''
run: |
curl -sS -X POST \
"$IONHOUR_BASE/deployments/${{ steps.ionhour_open.outputs.deploy_id }}/end" \
-H "Authorization: Bearer $IONHOUR_API_KEY"Swap /deployments for /maintenance-windows (with an endAt instead of ttlMinutes) when you want probing to keep running and only the alerting suppressed — for example, a schema migration where you still want latency data but no pages.