Gareth Wilson Gareth Wilson

Guide to Northflank Webhooks: Features and Best Practices

Published


Northflank webhooks tell your own systems what is happening on the platform: a build starts or fails, a job run finishes, an addon backup completes, an invoice goes unpaid, or a container crashes. Northflank already posts these notifications to Slack, Discord and Microsoft Teams, and the webhook integration type sends the same events to an HTTP endpoint you control, so you can open tickets, copy backups off-site or drive deployments from them.

This guide covers how Northflank webhook notification integrations are configured and authenticated, the event types they can send, Northflank's retry and resend behaviour, and the practices that keep a receiver safe and reliable.

What are Northflank webhooks?

A webhook notification integration is a destination you create on Northflank's notifications page. You give it a URL, an optional secret and the events you want, and Northflank sends a JSON POST to that URL each time one of those events happens.

Integrations exist at three levels. Account and team integrations can receive any event type and can be limited to selected projects or to resources with particular tags. Organisation integrations only receive billing events and provisioning errors for the organisation's clusters and node pools, and project and tag filters don't apply to them.

Northflank does not sign the payload. If you set a secret on the integration, Northflank sends it unchanged in the X-Northflank-Notification-Integration-Token header, and your receiver compares it with its own copy. Nothing is computed over the body.

Northflank webhook features

FeatureDetails
ConfigurationAccount, team or organisation settings, under Observability > Notifications
MethodPOST with a JSON body of event and data
AuthenticationOptional secret, sent verbatim in X-Northflank-Notification-Integration-Token
Body signatureNone
Replay windowNone. No timestamp is sent
FilteringEvent types, plus projects and resource tags for account and team integrations
SuccessAny 2xx response
RetriesResent "a limited number of times". The count and spacing aren't documented
Auto-disableWebhooks that keep failing are disabled automatically
Event historyEvery request, its headers and body, and each response, on the integration page
Manual resendAny request, from its event page

Northflank documents no response timeout, ordering guarantee or source IP addresses for webhook notifications.

Every request also carries headers that identify it:

HeaderContains
X-Northflank-Notification-Integration-IdID of the integration that sent the request
X-Northflank-Notification-Integration-NameName of that integration
X-Northflank-Notification-Integration-TokenThe integration's secret, if one is set
X-Northflank-Notification-Integration-Event-IdID of the event in the request
X-Northflank-Notification-Integration-Event-TypeThe event type, such as build:start

Common events

The create-notification-integration API lists 76 triggers. These are the groups most receivers start with:

AreaEventsFires when
Buildsbuild:start, build:success, build:failure, build:abortA build changes state
Deploymentsservice:deployment:status-updateA service deployment's status changes
Job runsjob-run:start, job-run:success, job-run:failure, job-run:abort, job-run:terminateA job run changes state
Addon backupsaddon-backup:start, addon-backup:success, addon-backup:failure, addon-backup:abortAn addon backup changes state
Billingbilling:invoice-paid, billing:invoice-payment-failed, billing:invoice-payment-action-required, billing:billing-alert-exceededAn invoice or billing alert changes
Infrastructureinfrastructure:service:container-crash, infrastructure:addon-volume:usage-90-exceeded and othersA container crashes or is evicted, CPU or memory stays above 90%, or a volume fills up

The rest cover service autoscaling, release flow, preview blueprint and template runs, certificates, CDN actions, paused log sinks, Tailscale key regeneration and errors on bring-your-own-cloud clusters. The API names each one with a trigger: prefix, as in trigger:build:start. The delivery in Northflank's docs carries build:start without it, in both the body and the event type header.

Here is Northflank's build:start example:

{
  "event": "build:start",
  "data": {
    "build": {
      "id": "social-hour-1312",
      "branch": "master",
      "pullRequestId": null,
      "status": "STARTING",
      "sha": "ca624abed0d5ba0ad6e6fe28c396196b81f0200d",
      "concluded": false,
      "createdAt": "2022-01-19T09:04:40.916Z"
    },
    "service": {
      "id": "website",
      "name": "Website"
    },
    "project": {
      "id": "personal-blog",
      "name": "Personal Blog"
    },
    "user": {
      "id": "thomas"
    }
  }
}

data holds the objects related to the event, here the build, its service and project, and the user who started it. Field names are camelCase. The body has no event ID or timestamp of its own: the event ID travels in the X-Northflank-Notification-Integration-Event-Id header. Build events are the only ones with a documented payload, so read data defensively for everything else and check a real delivery on the integration page before you rely on a field.

Setting up Northflank webhooks

  1. Build an endpoint that accepts POST requests and checks the token header.
  2. Generate a long random secret, for example with openssl rand -hex 32, or use the random generator in Northflank's form. Store it server-side as NORTHFLANK_WEBHOOK_SECRET. If your receiver runs on Northflank, add it as a runtime variable or secret file.
  3. Open Observability > Notifications in your account, team or organisation settings and create an integration with the Webhook type.
  4. Enter your endpoint URL and paste the secret.
  5. Select the events to receive, and optionally restrict the integration to projects or resource tags.
  6. Save, then trigger a matching event, such as starting a build, and check the request on the integration page.

The secret is optional in Northflank, but without one your endpoint can't tell Northflank's requests from anyone else's.

If you receive through Hookdeck, create a Northflank source, use its URL as the integration's webhook URL, and paste the same secret into the source's Webhook Secret field. Hookdeck accepts each request, then records any request whose X-Northflank-Notification-Integration-Token does not match as failed verification, so it never becomes an event for your service. Verification in Hookdeck is optional: leave it off if you didn't set a secret on the integration.

Securing Northflank webhooks

There is nothing to compute. Read X-Northflank-Notification-Integration-Token and compare it with your stored secret in constant time. Fail closed if no secret is configured, so a missing header can never match a missing secret. Northflank's own example uses !==; a constant-time comparison is safer.

const crypto = require('crypto');
const express = require('express');

function verifyNorthflankToken(headerValue, expectedSecret) {
  if (!headerValue || !expectedSecret) return false;
  const received = Buffer.from(headerValue, 'utf8');
  const expected = Buffer.from(expectedSecret, 'utf8');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

const app = express();

app.post('/webhooks/northflank', express.raw({ type: '*/*' }), (req, res) => {
  const secret = process.env.NORTHFLANK_WEBHOOK_SECRET;
  if (!secret) return res.sendStatus(500); // fail closed

  if (!verifyNorthflankToken(req.get('x-northflank-notification-integration-token'), secret)) {
    return res.sendStatus(401);
  }

  let body;
  try {
    body = JSON.parse(req.body.toString('utf8'));
  } catch {
    return res.sendStatus(400);
  }

  const event_id = req.get('x-northflank-notification-integration-event-id');
  // Queue { event_id, event: body.event, data: body.data } for processing.
  res.sendStatus(200);
});

The same check in Python:

import hmac


def verify_northflank_token(header_value, expected_secret: str) -> bool:
    if not header_value or not expected_secret:
        return False
    return hmac.compare_digest(header_value.encode("utf-8"), expected_secret.encode("utf-8"))


# In FastAPI: verify_northflank_token(
#     request.headers.get("x-northflank-notification-integration-token"),
#     os.environ["NORTHFLANK_WEBHOOK_SECRET"])

The token is a bearer secret: anyone who sees a request, in a log or a proxy, can reuse it. Serve the endpoint over HTTPS only, don't log request headers, and watch for trailing newlines when you load the secret from an environment file or secret file, as they are a common cause of failed comparisons.

Make Northflank webhooks production-ready. Hookdeck Event Gateway checks the Northflank token, acknowledges each notification straight away, and durably queues build, job and billing events before your service sees them.

Northflank webhook limitations and pain points

An optional token, not a signature

The Problem: Nothing proves the body came from Northflank unchanged, a captured request can be replayed, and an integration without a secret can't be authenticated at all.

Why It Happens: Northflank sends a static secret rather than a signature computed over the body, sends no timestamp, and lets you create an integration with no secret.

Workarounds:

  • Always set a secret, and use HTTPS only.
  • Before acting on anything that matters, such as downloading a backup or rolling back a deployment, confirm the resource's state with the Northflank API.
  • Use X-Northflank-Notification-Integration-Id to check the request came from the integration you expect.

How Hookdeck Can Help: Hookdeck holds the secret and checks it on every request, so your own services don't need it, and requests with a missing or wrong token never reach them.

Retries you can't plan around

The Problem: You can't tell how long a notification will be retried, and an endpoint that fails for a while can find its integration switched off.

Why It Happens: Northflank resends failed notifications "a limited number of times" without documenting the count, spacing or timeout, and automatically disables webhooks that keep failing.

Workarounds:

  • Return 2xx as soon as the request is authenticated and stored, and do slow work later.
  • Return 401 only for a bad token, so bugs in your handler don't count as delivery failures.
  • Check the integration page after any outage, re-enable the integration if needed, and resend missed requests from their event pages.

How Hookdeck Can Help: Hookdeck acknowledges each notification as soon as it arrives, so your service's downtime doesn't count against the integration. Hookdeck then retries delivery to your service on a schedule you set and lets you replay anything that failed.

Duplicates from resends

The Problem: A notification is handled twice, for example creating two tickets for the same failed job.

Why It Happens: Northflank resends a notification when it doesn't get a 2xx, including when your handler succeeded but the response was lost, and you can also resend manually.

Workarounds:

  • Deduplicate on the X-Northflank-Notification-Integration-Event-Id header.
  • Store the IDs you've handled for at least as long as Northflank keeps resending.

How Hookdeck Can Help: Hookdeck's deduplication can key on the event ID header and drop repeats before they reach your service.

Payloads you have to discover

The Problem: A handler written for one event type breaks on another, or misreads a field.

Why It Happens: Northflank documents the body for build events only. The other types share the event and data envelope, but the contents of data aren't published.

Workarounds:

  • Route on event and read data with optional chaining.
  • Subscribe in a non-production project first and inspect real deliveries on the integration page.
  • Log and acknowledge event types you don't handle, rather than failing them.

How Hookdeck Can Help: Hookdeck keeps every request with its full headers and body, so you can inspect real payloads for each type, and its filters can route each event type to a different destination.

Best practices

Authenticate before parsing

Check the token header before you parse or log the body, and return 401 when it fails.

Acknowledge fast and process asynchronously

Store the notification, return 2xx, then do the work, such as copying a finished backup or opening a ticket. See why to process webhooks asynchronously.

Make handlers idempotent

Use the event ID header as the key, and check whether you've already processed an event before acting on it. See our guide to webhook idempotency.

Keep integrations narrow

Subscribe only to the events a receiver handles, and use project and tag filters to cut noise. Separate integrations for builds, billing and infrastructure alerts, each with its own secret, are easier to reason about than one that receives everything.

Watch the integration page

The integration lists every request, the responses Northflank received and their status codes. Check it when a notification seems missing, and after an outage confirm the integration is still enabled.

Conclusion

Northflank webhooks are unsigned JSON POSTs from a notification integration, authenticated by an optional secret in X-Northflank-Notification-Integration-Token. Set a secret, compare it in constant time over HTTPS, route on event, deduplicate on the event ID header, and acknowledge quickly so the integration isn't marked as failing or disabled.

Hookdeck Event Gateway sits in front of your receiver, checks the Northflank token, and holds each event until your service has processed it.

Get started with Hookdeck for free and handle Northflank webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.