Ionhour Docs
Integrations

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:

DeploymentMaintenance window
EffectAuto-pauses the associated checksSuppresses alerts and incidents
ProbingStops (paused checks are not probed)Continues (data keeps flowing)
Use whenA release restarts or briefly breaks a servicePlanned work where you still want data but no noise
Resourcemcp:deploymentsmcp: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

MethodPathMin rolePurpose
POST/v1/deploymentsmemberOpen a deployment window (pauses checks).
POST/v1/deployments/:id/endmemberClose it (resumes paused checks).
GET/v1/deploymentsviewerList deployments.

Open a deployment

POST /v1/deployments

FieldTypeRequiredNotes
projectIdnumberYesThe project being deployed. Must belong to the key's workspace.
namestringNoHuman label (max 255).
versionstringNoRelease/version string (max 255).
authorstringNoWho triggered it (max 255).
linkstringNoURL back to the CI run (max 2048).
checkIdsnumber[]NoSpecific checks to pause. Omitted → all checks in the project.
autoPausebooleanNoPause the checks for the window. Defaults to true.
ttlMinutesnumberNoServer-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

MethodPathMin rolePurpose
POST/v1/maintenance-windowsmemberOpen a maintenance window (suppresses alerts/incidents).
POST/v1/maintenance-windows/:id/endmemberEnd it early.
GET/v1/maintenance-windowsviewerList windows.

Open a window

POST /v1/maintenance-windows

FieldTypeRequiredNotes
namestringYesWindow label (max 255).
endAtISO-8601YesWhen the window ends — its natural TTL. A background processor auto-completes the window past endAt.
descriptionstringNoMax 2000 chars.
startAtISO-8601NoDefaults to now.
projectIdsnumber[]NoProjects covered. Omitted → all projects in the workspace. Every id must belong to the workspace.
suppressAlertsbooleanNoDefaults to true.
suppressIncidentsbooleanNoDefaults 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.