Deployments & Maintenance
Announce deploys and maintenance windows from your own CI so Ionhour pauses probing or suppresses alerts while you work — including a GitHub Actions example.
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.
Webhooks
Receive Ionhour incidents and alerts into your IMS as signed HTTP callbacks — channel setup, payload format, event taxonomy, and signature verification steps.
Check Lifecycle
The complete state machine behind check status transitions — inbound and outbound flows, signal types, validation timing, and multi-region consensus rules.