{
  "openapi": "3.1.0",
  "info": {
    "title": "Pulsefast API",
    "version": "1",
    "description": "Manage monitors, maintenance windows and deploy markers, and read incidents, channels and status pages. JSON over HTTPS. Create a key under Account \u2192 API keys and send it as `Authorization: Bearer pf_\u2026`. 120 requests a minute per account. Docs: https://pulsefast.io/docs/api"
  },
  "servers": [
    {
      "url": "https://pulsefast.io"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Monitors"
    },
    {
      "name": "Maintenance"
    },
    {
      "name": "Deploys"
    },
    {
      "name": "Account"
    },
    {
      "name": "Inbound",
      "description": "Endpoints your systems call with a secret URL or token instead of an API key."
    }
  ],
  "paths": {
    "/api/v1/monitors": {
      "get": {
        "tags": [
          "Monitors"
        ],
        "operationId": "listMonitors",
        "summary": "List monitors",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Your monitors, with their current status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "monitors"
                  ],
                  "properties": {
                    "monitors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Monitor"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Monitors"
        ],
        "operationId": "createMonitor",
        "summary": "Create a monitor",
        "description": "Unset fields get your plan's defaults (the fastest interval it allows, timeout and retries).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorInput"
              },
              "example": {
                "name": "API",
                "url": "https://api.example.com/health",
                "interval_seconds": 30,
                "keyword": "ok",
                "channel_ids": [
                  3
                ]
              }
            }
          }
        },
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Monitor"
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/PlanLimit"
          },
          "422": {
            "$ref": "#/components/responses/Invalid"
          }
        }
      }
    },
    "/api/v1/monitors/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "Monitors"
        ],
        "operationId": "getMonitor",
        "summary": "Get a monitor",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "The monitor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Monitor"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Monitors"
        ],
        "operationId": "updateMonitor",
        "summary": "Update a monitor",
        "description": "Only the fields you send change. The type can't change.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorInput"
              },
              "example": {
                "paused": true
              }
            }
          }
        },
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Monitor"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Invalid"
          }
        }
      },
      "delete": {
        "tags": [
          "Monitors"
        ],
        "operationId": "deleteMonitor",
        "summary": "Delete a monitor",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "204": {
            "description": "Deleted, with its history."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/monitors/{id}/incidents": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "Monitors"
        ],
        "operationId": "listMonitorIncidents",
        "summary": "A monitor's incidents",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            }
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "incidents"
                  ],
                  "properties": {
                    "incidents": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Incident"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/maintenance": {
      "get": {
        "tags": [
          "Maintenance"
        ],
        "operationId": "listMaintenance",
        "summary": "List maintenance windows",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Upcoming, active and weekly windows.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "maintenance"
                  ],
                  "properties": {
                    "maintenance": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Maintenance"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Maintenance"
        ],
        "operationId": "createMaintenance",
        "summary": "Start or schedule a maintenance window",
        "description": "While a window is active, its monitors aren't checked or alerted, and the time doesn't count against uptime. Starts now unless `start` is set; covers every monitor unless `monitor_ids` is set.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MaintenanceInput"
              },
              "example": {
                "title": "Deploy",
                "duration_minutes": 15
              }
            }
          }
        },
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Maintenance"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Invalid"
          }
        }
      }
    },
    "/api/v1/maintenance/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "delete": {
        "tags": [
          "Maintenance"
        ],
        "operationId": "deleteMaintenance",
        "summary": "End or cancel a maintenance window",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "204": {
            "description": "Deleted; checks resume."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/deploys": {
      "get": {
        "tags": [
          "Deploys"
        ],
        "operationId": "listDeploys",
        "summary": "List deploys from the last 30 days",
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only this service's deploys."
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Newest first, up to 100.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deploys"
                  ],
                  "properties": {
                    "deploys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Deploy"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Deploys"
        ],
        "operationId": "createDeploy",
        "summary": "Record a deploy",
        "description": "Deploys made just before an incident are shown on it and sent to your agent, which looks at what changed first.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeployInput"
              },
              "example": {
                "service": "checkout",
                "version": "4f2a1c0e9b8d7a6f5e4d3c2b1a0f9e8d7c6b5a49",
                "environment": "production"
              }
            }
          }
        },
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "201": {
            "description": "Recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deploy"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Invalid"
          }
        }
      }
    },
    "/api/v1/channels": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "listChannels",
        "summary": "List alert channels",
        "description": "IDs to use in a monitor's `channel_ids`. Secrets are never returned.",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Your alert channels.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "channels"
                  ],
                  "properties": {
                    "channels": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Channel"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/status-pages": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "listStatusPages",
        "summary": "List status pages",
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "200": {
            "description": "Your status pages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status_pages"
                  ],
                  "properties": {
                    "status_pages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StatusPage"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/hb/{token}": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "From the heartbeat monitor's `heartbeat_url`."
        }
      ],
      "get": {
        "tags": [
          "Inbound"
        ],
        "operationId": "heartbeat",
        "summary": "Heartbeat ping",
        "description": "Your job calls this when it runs. GET, POST and HEAD all work. No API key: the token is the secret. At most 60 pings a minute.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown heartbeat."
          },
          "429": {
            "description": "Too many pings."
          }
        }
      }
    },
    "/hb/{token}/fail": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Inbound"
        ],
        "operationId": "heartbeatFail",
        "summary": "Report a failed run",
        "description": "Marks the heartbeat as failed right away, instead of waiting for it to go missing.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown heartbeat."
          }
        }
      }
    },
    "/in/{token}": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "The alert source's secret URL ends with it."
        }
      ],
      "post": {
        "tags": [
          "Inbound"
        ],
        "operationId": "receiveAlert",
        "summary": "Send an alert to an alert source",
        "description": "For a generic (JSON) source, send the schema below. Sources set to Alertmanager/Grafana, Sentry, Datadog or CloudWatch accept those tools' own webhook formats. 256 KB at most, 120 alerts a minute per source. Docs: https://pulsefast.io/docs/alert-sources",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Alert"
              },
              "example": {
                "title": "Checkout errors spiking",
                "key": "checkout-5xx",
                "severity": "critical"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "What happened to each alert.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "incident_id": {
                            "type": "integer"
                          },
                          "action": {
                            "type": "string",
                            "description": "opened, added, reopened, resolved, ignored or subscribed"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "description": "Unknown source URL."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/dispatches/{id}/status": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "example": "dsp_42"
        }
      ],
      "post": {
        "tags": [
          "Inbound"
        ],
        "operationId": "reportDispatchStatus",
        "summary": "Your agent reports on an incident",
        "description": "Authenticated with the dispatch's callback token (`Authorization: Bearer <token>` from the dispatch), not an API key. Tokens stop working when the incident closes. Docs: https://pulsefast.io/docs/agents",
        "security": [
          {
            "callbackToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StatusReport"
              },
              "example": {
                "status": "working",
                "note": "502s started after deploy abc123; checkout-worker OOMs on start."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The dispatch's state after the report.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "state": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key (pf_\u2026) from Account \u2192 API keys."
      },
      "callbackToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "The callback token sent with a dispatch."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed JSON or unknown fields.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or wrong key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found, or not yours.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PlanLimit": {
        "description": "Your plan's limit is reached.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Invalid": {
        "description": "A value isn't valid; the message says which.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests; wait for Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "Header": {
        "type": "object",
        "required": [
          "name",
          "value"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        }
      },
      "Monitor": {
        "type": "object",
        "required": [
          "id",
          "name",
          "type",
          "interval_seconds",
          "retries",
          "ssl_warn_days",
          "remind_seconds",
          "paused",
          "channel_ids",
          "status",
          "uptime_24h",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "http",
              "port",
              "heartbeat"
            ]
          },
          "url": {
            "type": "string",
            "description": "HTTP: the URL. Port: host:port. Absent for heartbeats."
          },
          "heartbeat_url": {
            "type": "string",
            "description": "Heartbeats only: where your job pings."
          },
          "interval_seconds": {
            "type": "integer",
            "description": "Checks: time between checks. Heartbeats: expected time between pings."
          },
          "timeout_seconds": {
            "type": "integer"
          },
          "grace_seconds": {
            "type": "integer",
            "description": "Heartbeats: extra time allowed after a missed ping."
          },
          "retries": {
            "type": "integer",
            "description": "Failed checks tolerated before the monitor is down."
          },
          "method": {
            "type": "string"
          },
          "header_names": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names only; header values are never returned."
          },
          "keyword": {
            "type": "string"
          },
          "keyword_absent": {
            "type": "boolean",
            "description": "The keyword must not appear."
          },
          "expect_status": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Accepted status codes; absent means any 2xx or 3xx."
          },
          "ssl_warn_days": {
            "type": "integer"
          },
          "remind_seconds": {
            "type": "integer",
            "description": "Repeat the down alert this often; 0 is never."
          },
          "paused": {
            "type": "boolean"
          },
          "channel_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "up",
              "down",
              "pending",
              "unknown",
              "paused",
              "suspended",
              "maintenance"
            ],
            "description": "suspended: beyond your plan's monitor count."
          },
          "uptime_24h": {
            "type": [
              "number",
              "null"
            ],
            "description": "0 to 1; null without checks."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MonitorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 80
          },
          "type": {
            "type": "string",
            "enum": [
              "http",
              "port",
              "heartbeat"
            ],
            "default": "http",
            "description": "Only when creating."
          },
          "url": {
            "type": "string"
          },
          "interval_seconds": {
            "type": "integer"
          },
          "timeout_seconds": {
            "type": "integer"
          },
          "grace_seconds": {
            "type": "integer"
          },
          "retries": {
            "type": "integer"
          },
          "method": {
            "type": "string",
            "enum": [
              "GET",
              "HEAD",
              "POST",
              "PUT",
              "PATCH",
              "DELETE",
              "OPTIONS"
            ]
          },
          "headers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Header"
            },
            "description": "Replaces all headers; stored encrypted."
          },
          "body": {
            "type": "string",
            "maxLength": 16384
          },
          "keyword": {
            "type": "string"
          },
          "keyword_absent": {
            "type": "boolean"
          },
          "expect_status": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "ssl_warn_days": {
            "type": "integer"
          },
          "remind_seconds": {
            "type": "integer"
          },
          "paused": {
            "type": "boolean"
          },
          "channel_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "Incident": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "resolved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "cause": {
            "type": "string"
          }
        }
      },
      "Maintenance": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "start": {
            "type": "string",
            "format": "date-time"
          },
          "end": {
            "type": "string",
            "format": "date-time"
          },
          "weekly": {
            "type": "boolean"
          },
          "time_zone": {
            "type": "string"
          },
          "monitor_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "MaintenanceInput": {
        "type": "object",
        "required": [
          "title",
          "duration_minutes"
        ],
        "additionalProperties": false,
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 80
          },
          "start": {
            "type": "string",
            "format": "date-time",
            "description": "Defaults to now."
          },
          "duration_minutes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1440
          },
          "weekly": {
            "type": "boolean",
            "description": "Repeat every week at this time, in time_zone."
          },
          "time_zone": {
            "type": "string",
            "default": "UTC",
            "description": "IANA name, like Europe/Lisbon."
          },
          "monitor_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Defaults to all monitors."
          }
        }
      },
      "Deploy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "service": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "environment": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DeployInput": {
        "type": "object",
        "required": [
          "version"
        ],
        "additionalProperties": false,
        "properties": {
          "service": {
            "type": "string",
            "maxLength": 60
          },
          "version": {
            "type": "string",
            "maxLength": 100,
            "description": "A commit SHA, tag or build number. A full 40-character SHA lets hosted agents check out exactly that commit."
          },
          "environment": {
            "type": "string",
            "maxLength": 40,
            "default": "production"
          },
          "url": {
            "type": "string",
            "description": "An http(s) link, e.g. to the CI run."
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "Defaults to now; within the last 30 days."
          }
        }
      },
      "Channel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "slack, discord, teams, telegram, ntfy, pushover, pagerduty, incidentio, webhook, email, sms, voice"
          }
        }
      },
      "StatusPage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "custom_domain": {
            "type": "string"
          },
          "monitor_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "Alert": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "What's wrong."
          },
          "key": {
            "type": "string",
            "description": "Groups alerts into one incident; defaults to the title."
          },
          "status": {
            "type": "string",
            "enum": [
              "firing",
              "resolved"
            ],
            "default": "firing"
          },
          "severity": {
            "type": "string",
            "enum": [
              "critical",
              "warning",
              "info"
            ],
            "default": "critical"
          },
          "details": {
            "description": "Anything: text or JSON. Kept as the raw alert."
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "StatusReport": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "working",
              "fix_proposed",
              "fixed",
              "gave_up"
            ]
          },
          "note": {
            "type": "string",
            "maxLength": 4000
          },
          "request_approval": {
            "type": "string",
            "description": "An action name (e.g. rollback_deploy) to ask the team to approve."
          },
          "fix": {
            "type": "object",
            "properties": {
              "branch": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "summary": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}
