Guides · October 21, 2026 · 7 min read

Flight change alerts in n8n, without polling

Two n8n templates that watch flights through FlightByte webhooks. One alerts Slack, email and SMS when a flight changes; one texts the driver when an airport pickup lands. No schedule trigger, no table of old values to compare.

The usual flight-alert workflow in n8n starts with a Schedule Trigger. Every thirty minutes it calls a flight API, reads the last known schedule from Postgres, works out what changed, writes the new values back, and then, a dozen nodes in, sends a message. Most of the workflow exists to compute a diff, and a gate change can still reach the passenger half an hour late.

FlightByte does the polling and the diff on its side, then sends one signed webhook per change with a list of exactly what changed. The n8n side shrinks to: receive, verify, decide who to tell. This guide covers two templates built that way.

  • Flight change alerts. A form adds a flight. Every change goes to Slack. Gate, time, delay, cancellation and diversion go to the passenger by email. Cancellations, diversions and arrival delays of an hour or more also go out by SMS.
  • Airport pickup. A form books a pickup. The driver gets a text when the flight leaves, when the landing time moves, when it reaches the gate, which belt the bags are on, or when it is cancelled or diverted.

Each name links to the workflow's JSON. Both use only n8n's built-in nodes, and both were built and tested on n8n 2.44.

What you need

  • n8n 2.x, reachable over HTTPS. n8n Cloud works as it is. A self-hosted n8n needs a public HTTPS address: FlightByte refuses webhook URLs on localhost or on private and loopback ranges.
  • A FlightByte API key. Get one free. Each flight you add is one watched flight on your plan.
  • The channels you want to use: a Slack app, a SendGrid key, a Twilio number. Delete the nodes you do not need.

Import and connect

1. Import the workflow. In n8n, open a new workflow, choose Import from URL in the workflow menu and paste:

https://flightbyte.dev/n8n/flight-change-alerts.json

2. Make up a signing secret. Every flight this workflow watches is signed with the same secret, so one webhook serves them all:

echo "whsec_$(openssl rand -hex 24)"

3. Connect FlightByte. Open Watch the flight and create a credential. Its type is already Custom Auth. Paste your key and the secret:

{
  "headers": { "x-api-key": "fb_live_..." },
  "body": { "secret": "whsec_..." }
}

The headers part authenticates the request. The body part is merged into every subscription the workflow creates, so FlightByte signs that flight's webhooks with your secret.

4. Give the webhook the same secret. Open Sign the raw body and create a Crypto credential. Put the same whsec_... value in Hmac Secret.

5. Connect the channels. Pick your channel in the three Slack nodes and set the sender in Email the passenger and Text the passenger.

6. Publish. Open the form's production URL, enter a flight, and the done page shows the subscription id.

Prove the webhook path

Before anything about the flight changes, send a test event. It goes through FlightByte's real pipeline, signed with the real secret:

curl -X POST "https://api.flightbyte.dev/v1/subscriptions/sub_.../test" \
  -H "x-api-key: $FLIGHTBYTE_KEY"

Within a second, Slack shows FlightByte test event received for sub_…. If nothing arrives, the delivery log says why:

curl "https://api.flightbyte.dev/v1/subscriptions/sub_.../deliveries" \
  -H "x-api-key: $FLIGHTBYTE_KEY"

A 401 there means the two credentials hold different secrets. A 404 means the workflow is not published.

How the workflow is laid out

Watching a flight

The form feeds Build the request, which turns tk 1848 into TK and 1848 and sets webhookUrl to the production URL of this workflow's own webhook. Watch the flight posts the subscription, and Remember who to tell saves the passenger's name, email and phone in an n8n data table called flightbyte_passengers, keyed by subscription id. The table is created on the first booking.

The contact details never leave n8n. FlightByte receives the flight and the booking reference in metadata, which comes back in every webhook. That is the same advice as everywhere else in these docs: put your own id in metadata, not a phone number.

To take bookings from Google Sheets, Airtable or your own system, swap the form and map the columns in Build the request.

Verifying the webhook

FlightByte signs <timestamp>.<raw body> with HMAC-SHA256 and sends the result as x-flightbyte-signature: t=…,v1=…. The signature covers the exact bytes it sent, so the check has to run on the raw body rather than on JSON that n8n has already parsed:

NodeWhat it does
FlightByte webhookRaw Body is on, so the original bytes arrive next to the parsed JSON. It answers through a Respond to Webhook node rather than straight away.
Raw body as textTurns those bytes into a string, unchanged.
Sign the raw bodyHMAC-SHA256 of the timestamp header, a dot and the raw body, keyed with the Crypto credential.
Signature valid?The result must match v1, and the timestamp must be less than five minutes old.
Accept (204) / Reject (401)Answers FlightByte within milliseconds, before any message is sent.
Skip retries already handledA retry carries the same event id. Remove Duplicates drops ids this workflow has already handled.

Keep the answer early

n8n's Respond to Webhook answers the first time execution reaches it. Keep both respond nodes directly after the check. If a slow node goes in front of them, FlightByte waits up to ten seconds and then retries.

The If node compares the two signatures with plain string equality. A service you write yourself should compare in constant time, as in verifying webhook signatures.

Who hears what

Event type sends each event down one branch:

EventWhat happens
flight.updatedThe passenger is looked up by subscription id, Write the messages writes the texts, and the passenger is told by email and SMS according to the rules below.
subscription.testA line in Slack, so you can see the path works.
subscription.suspendedA warning in Slack. FlightByte stops after twenty failed deliveries; resume with POST /v1/subscriptions/{id}/resume.
subscription.completedThe flight is over, so the passenger's row is deleted from the data table.

Write the messages starts with the rules, so changing who hears what means editing one list and one number:

// Change types a passenger hears about by email.
const EMAIL_CHANGES = [
  'flight.cancelled', 'flight.diverted', 'flight.reinstated', 'route.changed',
  'departure.gate.changed', 'departure.terminal.changed',
  'departure.scheduled.changed', 'departure.estimated.changed', 'delay.increased',
];
// Cancellations and diversions always go out by SMS,
// and so does an arrival delay of this many minutes or more.
const SMS_DELAY_MINUTES = 60;

Every change goes to Slack. Times in the webhook are UTC, and the messages show them in each airport's own time zone, so a passenger on TK1 sees the departure in Istanbul time and the arrival in New York time:

TK1 Istanbul to New York, 21 Oct: departs 14:00, gate D12
• Departure gate is now D12
• Departure time (estimated) is now 14:00, was 14:10
• Arrival time (estimated) is now 17:45, was 17:55

When the gate and runway times move together, only the gate time is shown. A flight that was watched some other way, with no row in the table, still reaches Slack.

Airport pickup

The pickup template has the same verification half and a shorter front half. Import https://flightbyte.dev/n8n/airport-pickup.json and connect the same two credentials. It needs only Twilio, and To WhatsApp on Text the driver switches the texts to WhatsApp.

Two things differ from the alerts workflow:

  • The subscription asks for less. Watch the flight sends an events filter: departed, arrived, cancelled, diverted, arrival time, arrival terminal and baggage belt. FlightByte only delivers those, so a departure gate change never wakes this workflow.
  • Small moves are skipped. Write the driver's text ignores arrival-time changes under MIN_SHIFT_MINUTES (ten by default), so the driver is not texted every time the estimate moves by two minutes.

The driver's phone stays in the flightbyte_pickups data table and is deleted when the flight completes. The texts read like this:

TK1 has left Istanbul. Lands about 17:45 at JFK. Passenger: Ayşe Yılmaz.
TK1 now lands about 18:10 at JFK (was 17:45). Passenger: Ayşe Yılmaz.
TK1 is at the gate at JFK, terminal 1. Bags on belt 7. Passenger: Ayşe Yılmaz.

When the form says no

The done page shows FlightByte's own error message. The usual ones:

MessageWhat to do
webhookUrl must use https, host "localhost" is not allowed or resolves to the non-public addressn8n does not know its public HTTPS address. Set WEBHOOK_URL on your n8n instance; Build the request uses it.
The flight number operates several legs that dayFill in Departure airport.
402, watched flight limitThe plan's monthly allowance is used. Existing watches keep running.
Invalid API keyCheck the x-api-key value in the Custom Auth credential.

A flight the airline has not published yet is accepted: the done page says so, and FlightByte starts watching when it appears. That works up to seven days ahead.

What it costs

Each form entry is one watched flight. The Free plan's three a month are enough to try both templates end to end. After that, Hobby covers a hundred flights for $9 and Starter five hundred for $19; the full table is on pricing.

Where next

More guides

Get started

Watch your first flight tonight.

Nine dollars, a hundred flights, every event, signed. The receiver above is the whole integration.

A free key in a minute, no card. Paid plans are paid by card in the dashboard.