Deploy Notifications

Outbound webhooks — get a signed POST to your URL on every deploy transition. Works with Slack, Discord, or anything that speaks HTTP.

Add a webhook

hatch webhook add https://example.com/hooks/deploys

A signing secret is generated and shown only once — store it. URLs must be https, private/loopback addresses are rejected, and each egg can have at most 3 webhooks.

Manage them with hatch webhook list, hatch webhook rm <id>, and hatch webhook test <id> (sends a ping event).

Events and payload

Each deploy transition fires one event: deploy.started, deploy.succeeded, or deploy.failed.

POST <your-url>
X-Hatch-Event: deploy.succeeded
X-Hatch-Signature: sha256=<HMAC-SHA256(body, secret)>
Content-Type: application/json

{
  "event": "deploy.succeeded",
  "slug": "myapp-xxxx",
  "deployment_id": "deploy_abc123",
  "image": "localhost:5000/myapp-xxxx:1776258831",
  "commit_sha": "8f16fa6",
  "timestamp": "2026-06-12T00:00:00Z"
}

Delivery is fire-and-forget: 5s timeout, one retry after 30s on network errors or 5xx. A failing webhook never blocks or fails your deploy.

Verify the signature

Recompute the HMAC-SHA256 of the raw body with your secret and compare:

// node
const crypto = require('crypto');
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.HATCH_WEBHOOK_SECRET)
  .update(rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-hatch-signature']));
# python
import hmac, hashlib
expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, request.headers['X-Hatch-Signature'])

Slack recipe

Create a Slack incoming webhook (api.slack.com → Incoming Webhooks) and register its URL:

hatch webhook add https://hooks.slack.com/services/T000/B000/XXXX

The payload is generic JSON (no per-provider formatting in v1) — Slack renders it as a code block, or point the webhook at a tiny relay if you want pretty messages.

Discord recipe

Discord accepts Slack-shaped JSON when you append /slack to a channel webhook URL:

hatch webhook add https://discord.com/api/webhooks/ID/TOKEN/slack

Or use the raw channel webhook URL without the suffix and handle the generic JSON in your own relay.

Hatch mascot