Webhooks

Events that arrive, signed, or tell you loudly that they did not.

Register an HTTPS endpoint, subscribe to the event types you care about, verify the signature on arrival and replay anything your receiver missed.

Subscribe

Create an endpoint with the event types you want. The signing secret is returned once — store it wherever your other secrets live.

Register an endpoint
curl -X POST https://api.flintwake.com/v2/webhooks/endpoints \
  -H "Authorization: Bearer $FLINTWAKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.acme.dev/flintwake",
    "events": ["wake.error", "slo.burn"]
  }'
HTTPS only, and redirects are not followed.

A redirect is indistinguishable from a hijack at delivery time, so we treat one as a failed attempt. Register the final URL.

Event types

  • wake.errorA captured request returned a 5xx status.
  • wake.slowA captured request exceeded the endpoint's latency objective.
  • replay.finishedA replay completed. The payload carries the response diff.
  • consumer.quota.warningA consumer crossed 80% or 95% of its allowance.
  • slo.burnAn availability or latency objective is burning error budget too fast.
  • key.rotatedA key was issued as a replacement for another key.
  • key.revokedA key was revoked, manually or on schedule.
  • webhook.disabledAn endpoint was disabled after seven days of 410 responses.

Subscribe to ["*"] if you would rather filter on your side. New event types are additive and never sent to an endpoint that did not ask for them.

Verify the signature

Every delivery carries x-flintwake-signature: a timestamp and an HMAC over the raw body. Verify before you parse, and reject anything older than five minutes.

The signature header
x-flintwake-signature: t=1789012458,v1=4f20a91c7b3e8d2a6c05f1b9e3d7a4c8b2e6f0d9
Verify
import { verifySignature } from "flintwake/webhooks";

app.post("/flintwake", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const event = verifySignature({
      payload: req.body,
      header: req.header("x-flintwake-signature"),
      secret: process.env.FLINTWAKE_WEBHOOK_SECRET,
      toleranceSeconds: 300,
    });
    handle(event);
    res.status(202).end();
  } catch {
    res.status(400).end();
  }
});

Retries and replay

  • Any response outside 2xx is a failure, as is a timeout after ten seconds.
  • We retry up to eight times with exponential backoff, spread over roughly eighteen hours.
  • After the eighth attempt the delivery is dead-lettered and kept for the retention window.
  • An endpoint returning 410 for seven consecutive days is disabled, and the account owner is told.

Replay is manual and deliberate. Once your receiver is healthy again, replay the dead-lettered deliveries from the console or the API — replays are marked as such so they are never confused with retries.

Replay a delivery
curl -X POST https://api.flintwake.com/v2/webhooks/deliveries/dlv_9f41d0/replay \
  -H "Authorization: Bearer $FLINTWAKE_API_KEY"

The delivery stream

Every attempt, its response code, its duration and its payload. Filter by status and replay anything that failed — this is the same component that ships on the console page.

Webhook deliveries
evt_9f41a2delivered
Endpoint
hooks.northbank.dev/flintwake
Event type
payment.settled
Attempt
1 of 8
Response
200
Duration
184ms
Payload
{
  "id": "evt_9f41a2",
  "type": "payment.settled",
  "created": 1789012458,
  "data": { "payment_id": "pi_3QkL2xB", "amount": 24900 }
}

Delivered on attempt 1. Signature verified by the receiver against the endpoint secret.