Skip to main content

API Reference

Webhook Events

Receive vendor incident notifications in your own system. Configure a webhook in Settings → Alerts, set a signing secret, then send a test to verify your receiver.

HTTP headers

Webhook requests use JSON. A configured secret adds the signature header. Channels can also include custom headers.
Content-Type
application/json

All webhook payloads are JSON-encoded.

X-Checkupstream-Signature
<64 lowercase hex characters>

HMAC-SHA256 of the raw request body using your webhook secret, with no algorithm prefix. Included only when a secret is configured. Verify the signature before processing the event.

Verifying signatures

Always verify the X-Checkupstream-Signature header before processing events. The value is an HMAC-SHA256 hash of the raw request body, hex-encoded with no algorithm prefix.
TypeScript
import crypto from "node:crypto";

export function verifySignature(
  body: string,
  signature: string,
  secret: string,
): boolean {
  // Check the format before decoding untrusted header values.
  if (!/^[0-9a-f]{64}$/i.test(signature)) return false;
  const expected = crypto.createHmac("sha256", secret).update(body).digest();
  return crypto.timingSafeEqual(Buffer.from(signature, "hex"), expected);
}

Event payloads

Incident alerts, SDK failure alerts, updates, record closures and tests use different flat payloads. These examples are illustrative. Dependency matches and generated enrichment do not confirm application impact.

incident.detected

Sent when a vendor declares an active incident, outside maintenance, on a service your organization tracks. For a service scoped to certain components, the vendor must name one of them. impact is the vendor's own label, passed through unaltered; it never decides whether we send.

Illustrative payload
{
  "event": "incident.detected",
  "rule": "vendor_incident",
  "serviceId": "svc_stripe",
  "serviceName": "Stripe",
  "incidentId": "inc_abc123",
  "title": "Elevated error rates on the Charges API",
  "impact": "major_outage",
  "componentNote": "Vendor named components: Charges API",
  "sdkFailures": null,
  "affectedProjects": [
    {
      "id": "prj_checkout",
      "name": "checkout-api",
      "dependencies": [
        { "name": "stripe", "version": "14.12.0", "ecosystem": "npm" }
      ]
    }
  ],
  "failedLookups": [],
  "enrichment": {
    "aiSummary": "Card charges are failing for a subset of requests.",
    "affectedCapabilities": ["Card payments"],
    "survivingCapabilities": ["Subscription billing"],
    "mitigations": ["Queue charge retries behind an idempotency key"],
    "architectureInsight": null,
    "affectedProjects": [
      {
        "id": "prj_checkout",
        "name": "checkout-api",
        "dependencies": [
          { "name": "stripe", "version": "14.12.0", "ecosystem": "npm" }
        ]
      }
    ],
    "affectedRegions": ["us-east-1"],
    "recurrenceCount7d": 2,
    "source": "ai-cached"
  },
  "timestamp": "2026-04-06T14:32:00Z"
}

sdk.failures

Sent when your own SDK's calls to a vendor fail: at least 5% of at least 20 calls in a five-minute window returned a 5xx response, a network error or a timeout. 4xx responses are not counted. sdkFailures.threshold carries the values that applied. One alert covers consecutive failing windows.

Illustrative payload
{
  "event": "sdk.failures",
  "rule": "sdk_failures",
  "serviceId": "svc_stripe",
  "serviceName": "Stripe",
  "incidentId": "",
  "title": "38 of 412 calls to api.stripe.com failed (5xx/timeouts), 14:05–14:10 UTC, from your SDK",
  "impact": "",
  "componentNote": null,
  "sdkFailures": {
    "hostnames": ["api.stripe.com"],
    "failedCalls": 38,
    "totalCalls": 412,
    "windowStart": "2026-04-06T14:05:00.000Z",
    "windowEnd": "2026-04-06T14:10:00.000Z",
    "threshold": { "failureRatio": 0.05, "minCalls": 20 }
  },
  "affectedProjects": [],
  "failedLookups": [],
  "enrichment": {
    "aiSummary": null,
    "affectedCapabilities": [],
    "survivingCapabilities": [],
    "mitigations": [],
    "architectureInsight": null,
    "affectedProjects": [],
    "affectedRegions": [],
    "recurrenceCount7d": null,
    "source": "structural-only"
  },
  "timestamp": "2026-04-06T14:16:00Z"
}

incident.updated

Sent after a status or severity change to the original webhook URL, while its channel is enabled and the alert remains unmuted. Read impact for the current severity and updateBody for the vendor's update.

Illustrative payload
{
  "event": "incident.updated",
  "kind": "incident_updated",
  "serviceId": "svc_stripe",
  "serviceName": "Stripe",
  "incidentId": "inc_abc123",
  "title": "Elevated error rates on the Charges API",
  "status": "monitoring",
  "impact": "degraded",
  "updateBody": "We are monitoring the results of a fix.",
  "timestamp": "2026-04-06T15:02:00Z"
}

incident.resolved

Sent when a tracked record closes, to the original webhook URL while its channel is enabled and the alert remains unmuted. Read resolution before interpreting the event as vendor recovery.

vendor_declared
The vendor explicitly reported its incident resolved. Application recovery still needs your own evidence.
absent_from_feed
The incident disappeared from the vendor feed. No vendor resolution was recorded.
unspecified
The record closed without a recognized reason. Vendor recovery is unconfirmed.

The duration field is a human-readable interval between the record’s start and closure timestamps, such as 42m. It is not measured application downtime.

Illustrative payload
{
  "event": "incident.resolved",
  "kind": "incident_resolved",
  "serviceId": "svc_stripe",
  "serviceName": "Stripe",
  "incidentId": "inc_abc123",
  "title": "Elevated error rates on the Charges API",
  "resolution": "absent_from_feed",
  "duration": "42m",
  "timestamp": "2026-04-06T15:14:00Z"
}

alert.test

Sent when you press "Send test" on a webhook channel in Settings → Alerts. If a secret is configured, the test uses it to sign the request. Use this event to check your receiver before an incident.

Illustrative payload
{
  "event": "alert.test",
  "service": "Stripe",
  "title": "Test alert from CheckUpstream",
  "timestamp": "2026-04-06T14:32:00Z"
}

Ready to receive events

Add your endpoint and secret, then use Send test to check signature handling and delivery.