FlightByte

Quickstart

Look a flight up, subscribe to it, receive and verify the first webhook.

You need an API key and an HTTPS endpoint that can receive a POST. If you have neither yet, request a key and use a tunnel such as ngrok or cloudflared for the endpoint while you develop.

1. Look a flight up

Flights are addressed by airline code, flight number and the local departure date at the origin.

curl "https://api.flightbyte.dev/v1/flights/TK/1848/2026-09-12" \
  -H "x-api-key: $FLIGHTBYTE_KEY"

The response is the flight snapshot, trimmed here to the parts most code reads first:

{
  "flightKey": "TK1848:2026-09-12@ATH-IST",
  "carrier": { "iata": "TK", "icao": "THY", "name": "Turkish Airlines" },
  "departure": {
    "airport": { "iata": "ATH", "name": "Athens Eleftherios Venizelos International Airport", "city": "Athens", "timezone": "Europe/Athens" },
    "terminal": "M",
    "gate": "A11",
    "times": {
      "scheduledGate": { "utc": "2026-09-12T09:10:00.000Z", "local": "2026-09-12T12:10:00.000", "timezone": "EEST" }
    },
    "bestTimeUtc": "2026-09-12T09:10:00.000Z",
    "delayMinutes": null
  },
  "arrival": { "airport": { "iata": "IST" }, "baggage": null, "times": { "scheduledGate": { "utc": "2026-09-12T10:45:00.000Z" } } },
  "status": { "code": "S", "label": "Scheduled", "phase": "scheduled", "delayed": false, "cancelled": false, "diverted": false },
  "equipment": { "tailNumber": "TC-LTP", "iata": "32Q", "name": "Airbus A321neo" },
  "alternates": [],
  "cached": false
}

Two legs, one number

Some flight numbers fly twice on the same day. If the one you asked for does, the response describes the upstream's default leg and lists every leg under alternates; pass ?origin=ATH to choose. Flights → Leg selection has the details.

2. Subscribe

One subscription watches one flight on one date. Give it the URL to call and, optionally, which change types you want.

curl -X POST "https://api.flightbyte.dev/v1/subscriptions" \
  -H "x-api-key: $FLIGHTBYTE_KEY" \
  -H "content-type: application/json" \
  -d '{
    "carrier": "TK",
    "flightNumber": "1848",
    "date": "2026-09-12",
    "webhookUrl": "https://yourapp.com/hooks/flights",
    "events": ["flight.departed", "flight.arrived", "delay.increased", "arrival.gate.changed"],
    "metadata": { "bookingId": "BK-1042" }
  }'
201 Created (trimmed)
{
  "id": "sub_7fd9fa92faf3475db99b",
  "status": "active",
  "flightKey": "TK1848:2026-09-12@ATH-IST",
  "webhookUrl": "https://yourapp.com/hooks/flights",
  "secret": "whsec_Y0Cp2VtM9s8Lq2fXo1nD3a7MA0u",
  "events": ["flight.departed", "flight.arrived", "delay.increased", "arrival.gate.changed"],
  "metadata": { "bookingId": "BK-1042" }
}

Store the secret: it is shown in full only in this response, and you need it to verify deliveries. metadata is opaque to FlightByte and comes back in every webhook, which is how you map a delivery to your own record.

A subscription.created event is delivered right away, so you can confirm the endpoint works before anything about the flight changes.

3. Receive and verify

Every delivery is a POST with a JSON body and a signature header. Verify the signature, check the timestamp, then act on changes.

import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.FLIGHTBYTE_WEBHOOK_SECRET!;

// The signature covers the raw body; parse it only after verifying.
app.post("/hooks/flights", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.header("x-flightbyte-signature") ?? "";
  const [t, v1] = header.split(",").map((part) => part.split("=")[1]);
  const expected = createHmac("sha256", SECRET).update(`${t}.${req.body}`).digest("hex");

  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  const valid = v1?.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
  if (!fresh || !valid) return res.status(401).end();

  const event = JSON.parse(req.body.toString());
  for (const change of event.changes) console.log(event.flightKey, change.type, change.message);
  res.status(204).end();
});

Respond with any 2xx within ten seconds. Anything else is retried with backoff; Webhooks → Retries explains the schedule.

4. Send a test event

You do not have to wait for a real gate change to see the pipeline work:

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

A subscription.test event goes through the same signing, delivery and logging as a real one. Then read what happened:

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

Each entry carries the HTTP status your endpoint returned, the latency, the attempt number and any error, so a misbehaving receiver is visible from the API rather than from a guess.

On this page