Back to Blog
Guide10 min read2026-07-09

How to Set Up Deployment Webhooks

Webhooks let you trigger deploys and react to deploy events automatically. This guide covers inbound deploy hooks, outbound notifications, securing webhooks with signatures, and building reliable handlers.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Two directions of deployment webhooks

"Deployment webhooks" covers two related but distinct flows, and it's worth separating them:

  1. 1Inbound (deploy hooks): an external system calls *your platform* to trigger a deployment. Example: a CMS publish, a CI pipeline, or a cron service POSTs to a URL and your app redeploys.
  2. 2Outbound (deploy notifications): *your platform* calls external systems when a deploy event happens. Example: notify Slack, update a status page, kick off a smoke-test job, or invalidate a CDN cache when a deploy succeeds.

Both are just HTTP POSTs, but they have different security and reliability concerns.

Inbound: triggering a deploy with a hook

A deploy hook is a secret URL that, when POSTed to, starts a deployment. The classic use is decoupling content from code: your marketing team publishes in a headless CMS, the CMS fires a webhook, and your static site rebuilds, no developer involved.

# Trigger a rebuild by POSTing to a deploy hook URL
curl -X POST "https://deploy.example.com/hooks/abcdef123456"

The security model here is the secret in the URL, so treat that URL like a password: don't commit it, rotate it if it leaks, and prefer URLs that are long and random. For higher security, layer a signature or token on top rather than relying on the URL alone.

Outbound: reacting to deploy events

When a deploy starts, succeeds, or fails, you often want to *do something*: post to a team channel, record the release in your error tracker, run integration tests, or warm a cache. The pattern is to register a handler URL that receives an event payload.

{
  "event": "deploy.succeeded",
  "service": "api",
  "commit": "abc123",
  "environment": "production",
  "timestamp": "2026-03-30T10:15:00Z"
}

Your handler reads the event and acts on it. This is how you build a deploy pipeline that fans out to the rest of your tooling.

Securing webhooks: verify signatures

The most important security practice for *receiving* webhooks: verify the payload signature. Anyone who learns your handler URL can POST fake events unless you authenticate them. The standard approach is HMAC, the sender signs the payload with a shared secret and includes the signature in a header; you recompute it and compare.

const crypto = require('crypto');

function verify(req, secret) {
  const signature = req.headers['x-signature'];
  const expected = crypto
    .createHmac('sha256', secret)
    .update(req.rawBody)            // verify the RAW body, before JSON parsing
    .digest('hex');
  // constant-time compare to avoid timing attacks
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Two critical details: sign the raw body (not the re-serialized JSON, which may differ byte-for-byte), and use a constant-time comparison to avoid timing attacks.

Building reliable handlers

Webhook delivery is best-effort, and good senders retry on failure. That has consequences for your handler:

  • Respond fast (2xx) immediately, then do the work. If you do slow work before responding, the sender may time out and retry, causing duplicates. Acknowledge first, process async.
  • Be idempotent. Because of retries, the same event may arrive twice. Use the event ID (or a dedupe key) to ignore duplicates.
  • Return the right status. 2xx = received; 4xx = don't retry (bad request); 5xx = retry later. Returning 200 on a failure means the sender won't retry a delivery you actually dropped.
app.post('/webhooks/deploy', async (req, res) => {
  if (!verify(req, process.env.WEBHOOK_SECRET)) return res.sendStatus(401);
  res.sendStatus(200);                       // acknowledge immediately
  const id = req.body.id;
  if (await alreadyProcessed(id)) return;     // idempotent
  await enqueue(req.body);                     // do the work async
});

Webhooks with PandaStack deployments

PandaStack's core model is git-push deploys: pushing to your connected repo triggers a build and deploy automatically, which covers the most common "trigger a deploy" need without any manual webhook at all. For the cases where you want to react to deploy events or trigger work from external systems, webhooks fill the gap:

  • Outbound reactions: build a small handler service (deployed on PandaStack as a container) that receives deploy events and fans them out, post to Slack, run smoke tests against the new release, or invalidate a cache. Because PandaStack keeps deploy history and supports rollbacks, a failure notification can prompt an immediate rollback.
  • Inbound triggers: deploy a lightweight endpoint (a container or an edge function) that authenticates an incoming request and kicks off downstream work, for example, a CMS publish that triggers a content sync cronjob or a cache warm.

Store your webhook secrets as environment variables on the service (never in the repo), and use PandaStack's live logs to debug deliveries, watching the handler's logs as events arrive is the fastest way to diagnose signature or payload issues.

# Secret lives in the service env, not the code:
WEBHOOK_SECRET=...
# Handler verifies HMAC, responds 200 fast, processes async.

Testing webhooks

  • Use a tool like ngrok or a request-bin service to inspect payloads during development.
  • Send a known payload and confirm your signature verification passes for valid and fails for tampered bodies.
  • Simulate a duplicate delivery and confirm idempotency holds.
  • Simulate a slow handler and confirm you still acknowledge quickly.

Conclusion

Deployment webhooks come in two flavors, inbound triggers and outbound notifications, but both are HTTP POSTs that demand the same care: verify signatures against the raw body with a constant-time compare, acknowledge fast and process asynchronously, and make handlers idempotent because retries will resend events. Get those right and webhooks become a reliable backbone for automating your deploy pipeline.

PandaStack gives you git-push deploys out of the box plus the containers, edge functions, and live logs to build robust webhook handlers around your deploys. Try it on the free tier at https://dashboard.pandastack.io.

References

  • GitHub, securing webhooks with signatures: https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries
  • Stripe webhook best practices: https://docs.stripe.com/webhooks
  • HMAC (RFC 2104): https://datatracker.ietf.org/doc/html/rfc2104
  • OWASP, webhook/SSRF considerations: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also