Webhooks

Tell your group chat the moment Zack is a dad

Point us at a Discord channel, a Slack channel or your own server, and we'll post there when labour starts and when the baby arrives. Optionally, every day until then, to confirm that nothing has happened.

Add a webhook

A Discord or Slack incoming webhook, or any HTTPS endpoint that accepts JSON.

How it works

You'll get a secret management link to test or delete it. At most 500 webhooks, so the stork doesn't get repetitive strain injury.

Formats

  • Discord (discord.com/api/webhooks/…): a message with an embed, coloured by the answer. Nobody gets pinged.
  • Slack (hooks.slack.com/…): a message with a header and the details.
  • Generic JSON: anything else. Signed, so you can tell it's really us.

Generic JSON webhooks

We POST a JSON body with these headers:

Content-Type
application/json
X-Iszackadad-Event
update for real news; hello, test or goodbye for housekeeping. Only act on update.
X-Iszackadad-Signature
sha256=<hex>: an HMAC-SHA256 of the raw body, keyed with your webhook's token.
X-Iszackadad-Delivery
A delivery id, for de-duplicating if you're that sort of person.

The body looks like this (state.status is no, soon or yes):

{
  "event": "update",
  "update": {
    "id": 42,
    "kind": "status",
    "title": "Zack is a dad!",
    "body": "Zack is a dad! The baby is here.",
    "status": "yes",
    "audience": "all",
    "createdAt": "2026-11-20T03:14:15.926Z",
    "notifiedAt": null
  },
  "state": {
    "status": "yes",
    "statusChangedAt": "2026-11-20T03:14:15.926Z",
    "dueDate": null
  },
  "url": "https://iszacka.dad/updates/42",
  "sentAt": "2026-11-20T03:15:16.000Z"
}

Check the signature before believing a word of it. In Node:

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: the request body exactly as received (a Buffer or string), before JSON.parse.
function isFromTheStork(rawBody, signatureHeader) {
  const expected = 'sha256=' + createHmac('sha256', "<the token at the end of your management link>").update(rawBody).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(String(signatureHeader ?? ''));
  return a.length === b.length && timingSafeEqual(a, b);
}

Reply with any 2xx within 10 seconds. A 404 or 410 unsubscribes you on the spot. Anything else counts as a failure, and 10 in a row switches the webhook off. Redirects aren't followed.