{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/getvigilia-com/json-schema/getvigilia-com-incident-schema.json",
  "title": "Incident",
  "x-generated": "2026-11-10",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/getvigilia-com-openapi.json#/components/schemas/Incident",
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "appId": {
      "type": "string"
    },
    "kind": {
      "type": "string",
      "enum": [
        "error",
        "downtime",
        "health"
      ],
      "description": "error: errors from real visitors, diagnosed. downtime: the uptime checker. health: a recurring check of the app itself (secret keys in its public code, its certificate)."
    },
    "check": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "secrets",
        "certificate",
        "domain",
        "speed",
        null
      ],
      "description": "Health incidents: which check raised it. `speed`: the app answers several times slower than its usual."
    },
    "details": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Health incidents: the specifics, e.g. each exposed key, masked, and where it was found. Empty otherwise."
    },
    "endpoint": {
      "type": [
        "object",
        "null"
      ],
      "description": "Downtime incidents about one of the app's extra check URLs (a page such as checkout, or an API), rather than the whole app. Null otherwise.",
      "properties": {
        "url": {
          "type": "string"
        },
        "label": {
          "type": [
            "string",
            "null"
          ],
          "description": "The owner's name for it, e.g. Checkout."
        }
      },
      "required": [
        "url",
        "label"
      ]
    },
    "sentry": {
      "type": [
        "object",
        "null"
      ],
      "description": "The Sentry issue this incident explains, when it came through the Sentry bridge (Team). Null otherwise.",
      "properties": {
        "url": {
          "type": "string"
        }
      },
      "required": [
        "url"
      ]
    },
    "issue": {
      "type": [
        "object",
        "null"
      ],
      "description": "The issue opened for this incident in GitHub Issues, Linear or Jira (Team plan), by hand or automatically. Null when there is none.",
      "properties": {
        "tracker": {
          "type": "string",
          "enum": [
            "github",
            "linear",
            "jira"
          ]
        },
        "url": {
          "type": "string"
        },
        "key": {
          "type": "string",
          "description": "#123, ENG-45, SHOP-7"
        }
      },
      "required": [
        "tracker",
        "url",
        "key"
      ]
    },
    "related": {
      "type": [
        "object",
        "null"
      ],
      "description": "The same problem seen from the other side: for a request that failed with a 5xx in visitors' browsers, the server error behind it (side: server); for a server error, the failed request visitors saw (side: browser). Null when there is none.",
      "properties": {
        "side": {
          "type": "string",
          "enum": [
            "server",
            "browser"
          ]
        },
        "incidentId": {
          "type": [
            "string",
            "null"
          ]
        },
        "title": {
          "type": "string"
        },
        "count": {
          "type": "integer"
        }
      },
      "required": [
        "side",
        "incidentId",
        "title",
        "count"
      ]
    },
    "severity": {
      "type": "string",
      "enum": [
        "critical",
        "high",
        "medium",
        "low"
      ]
    },
    "status": {
      "type": "string",
      "enum": [
        "open",
        "resolved",
        "ignored"
      ]
    },
    "title": {
      "type": "string"
    },
    "summary": {
      "type": "string",
      "description": "What broke, in plain language."
    },
    "userImpact": {
      "type": "string",
      "description": "Who is affected and how."
    },
    "occurrences": {
      "type": [
        "integer",
        "null"
      ]
    },
    "sessions": {
      "type": [
        "integer",
        "null"
      ]
    },
    "isRegression": {
      "type": "boolean",
      "description": "It was marked fixed and came back."
    },
    "createdAt": {
      "type": "integer"
    },
    "updatedAt": {
      "type": "integer"
    },
    "resolvedAt": {
      "type": [
        "integer",
        "null"
      ]
    },
    "fix": {
      "type": "object",
      "properties": {
        "watch": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "watching",
            "verified",
            "not_enough_traffic",
            "unverified",
            null
          ],
          "description": "`watching` until there is a verdict. `verified`: the error stayed away through enough traffic that it would very likely have shown again. `not_enough_traffic`: watched for 7 days without enough traffic to say either way. `unverified` is the same outcome as recorded before October 2026."
        },
        "verifiedAt": {
          "type": [
            "integer",
            "null"
          ]
        },
        "evidence": {
          "type": [
            "object",
            "null"
          ],
          "description": "The traffic behind the verdict, or behind the wait so far. Null until the watch is first examined, 24 hours after the incident is resolved.",
          "properties": {
            "expectedErrors": {
              "type": "number",
              "description": "How many times the error would have shown up since the fix, had the fix done nothing: its rate per visit in the week before the fix, times the visits since. A fix is confirmed at 3 or more."
            },
            "visits": {
              "type": "integer",
              "description": "Production page loads since the incident was resolved."
            },
            "baselineHits": {
              "type": "integer",
              "description": "Sessions the error hit in the 7 days before the incident was resolved."
            },
            "baselineVisits": {
              "type": "integer",
              "description": "Production page loads in those 7 days."
            },
            "measured": {
              "type": "boolean",
              "description": "False when traffic for this error cannot be counted yet (errors from the app's backend). Its fix then cannot be confirmed."
            },
            "countedAt": {
              "type": "integer"
            }
          }
        }
      }
    },
    "dashboardUrl": {
      "type": "string"
    },
    "afterDeploy": {
      "type": [
        "object",
        "null"
      ],
      "description": "The deploy this problem first appeared after, within a day. Timing, not blame.",
      "properties": {
        "at": {
          "type": "integer"
        },
        "label": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "providerOutage": {
      "type": [
        "object",
        "null"
      ],
      "description": "A platform the app depends on (Supabase, Vercel, OpenAI…) was reporting its own incident when this began, from its public status page. There may be nothing to fix in the app. `resolvedAt` is set once the provider marks it resolved; if the problem continues after that, the cause is likely the app's.",
      "properties": {
        "provider": {
          "type": "string"
        },
        "incident": {
          "type": "string",
          "description": "The provider's own title for its incident."
        },
        "level": {
          "type": "string",
          "enum": [
            "outage",
            "degraded"
          ]
        },
        "url": {
          "type": "string",
          "description": "The provider's status page for this incident."
        },
        "startedAt": {
          "type": "integer"
        },
        "resolvedAt": {
          "type": [
            "integer",
            "null"
          ]
        }
      }
    }
  }
}