Node.js SDK
The official FlightByte library for Node.js and TypeScript. Look a flight up, watch it, and verify signed flight status webhooks on Node, Bun, Deno, Cloudflare Workers, Next.js and Express.
flightbyte on npm is the official Node.js and TypeScript client for the FlightByte flight status API. It looks flights up, watches them so every gate change, delay, departure and landing arrives as a signed webhook, and verifies each delivery in one call. It ships its own types, has no dependencies, and runs wherever fetch and Web Crypto do: Node 20.19 and later, Bun, Deno, Cloudflare Workers and Vercel Edge.
Source: flightbyte-node on GitHub, MIT license. Package: flightbyte on npm.
Install
npm install flightbyte| Package manager | Command |
|---|---|
| npm | npm install flightbyte |
| pnpm | pnpm add flightbyte |
| Yarn | yarn add flightbyte |
| Bun | bun add flightbyte |
| Deno | deno add npm:flightbyte |
The package is ES modules, and require() works on Node 20.19 and later. You need an API key: the free plan covers three watched flights a month, no card.
Look a flight up
import { FlightByte } from 'flightbyte';
const client = new FlightByte({ apiKey: process.env.FLIGHTBYTE_API_KEY! });
const flight = await client.flights.get({
carrier: 'TK',
flightNumber: '1848',
date: '2026-09-08', // local departure date at the origin
});
console.log(flight.status.label); // Scheduled
console.log(flight.departure.gate); // A11
console.log(flight.departure.delayMinutes); // 15Every field autocompletes. The date is the local departure date at the origin airport; FlightByte.formatDate(new Date(), 'Europe/Istanbul') gives it in the YYYY-MM-DD form the API expects. A number that flies more than one leg that day, such as TK1, lists every leg in alternates: pass origin: 'IST' to pick one. The full snapshot is under Flights.
Watch a flight
const created = await client.subscriptions.create(
{
carrier: 'TK',
flightNumber: '1848',
date: '2026-09-08',
webhookUrl: 'https://api.example.com/hooks/flights',
events: ['departure.gate.changed', 'delay.increased', 'flight.departed'],
metadata: { bookingId: 'BK-1042' },
},
{ idempotencyKey: 'BK-1042' }, // a retry never counts twice
);
// Shown in full only now: store it where your webhook receiver can read it.
const signingSecret = created.secret;A subscription is one watched flight on your plan, however many changes it sends. Ten travellers on the same flight are one watched flight when you subscribe once and pass each change on to all ten. FlightByte delivers to public HTTPS addresses only: on your machine, expose the port with cloudflared tunnel --url http://localhost:8080 or ngrok http 8080 and use that URL. client.subscriptions.sendTest(id) sends a signed subscription.test whenever you want to see the path work.
The other calls: list, listAll (every page, with for await), get, update, pause, resume, delete, deliveries, events, secret and rotateSecret. Every method takes a last argument with a signal to cancel it and a timeoutMs of its own.
Receive webhooks
A receiver verifies the signature against the raw body, skips an event id it has seen, answers 2xx within ten seconds and does the work afterwards. Webhook.fetchHandler does the first and answers for you: 401 for a bad signature, 400 for a body that is not an event, 500 when your function throws, so FlightByte retries, and 200 otherwise.
import { Webhook } from 'flightbyte';
const receive = Webhook.fetchHandler(process.env.FLIGHTBYTE_WEBHOOK_SECRET!, async (event) => {
if (!(await markHandled(event.id))) return; // a retry carries the same id
queue.push(event); // answer first, work afterwards
});It takes a Request and returns a Response, so it mounts as it is in every runtime built on them:
// app/api/flightbyte/route.ts
export const POST = receive;Express
Give the route the raw body with express.raw, not express.json. The signature covers the bytes as sent, and JSON parsed and serialised again no longer matches.
import express from 'express';
import { Webhook, WebhookSignatureError } from 'flightbyte';
app.post('/hooks/flightbyte', express.raw({ type: 'application/json' }), async (req, res) => {
let event;
try {
event = await Webhook.constructEvent(req.body, req.get(Webhook.SIGNATURE_HEADER), signingSecret);
} catch (err) {
return res.sendStatus(err instanceof WebhookSignatureError ? 401 : 400);
}
res.sendStatus(200);
switch (event.type) {
case 'flight.updated':
for (const change of event.changes) console.log(`${event.flightKey} ${change.type}: ${change.message}`);
break;
case 'subscription.completed':
console.log(`${event.flightKey} finished`);
break;
}
});An empty secret throws a TypeError at once, because anyone can sign with an empty key: an unset environment variable fails at startup instead of accepting forged events. The check is HMAC-SHA256 over "<t>." + raw body, compared in constant time with crypto.subtle.verify, with a timestamp more than five minutes off rejected. Verifying webhook signatures explains each step, and Webhooks has the payload and the 23 change types.
Errors
Every failed request rejects with a subclass of FlightByteError, so you branch with instanceof.
| Error | Status | What to do |
|---|---|---|
BadRequestError | 400 | Fix the input; messages has a line per field. For a number that flies twice, legs lists them: pass one's origin. |
AuthenticationError | 401 | The key is missing, invalid, revoked or expired. |
PaymentRequiredError | 402 | No watched flights left. code is watched_flight_limit, overage_cap_reached (see resetsAt) or credits_exhausted (see balance and expiresAt). |
PermissionDeniedError | 403 | The account is suspended, or a token lacks the scope. |
NotFoundError | 404 | The flight did not operate that day, or there is no such subscription. |
RateLimitError | 429 | A minute, day or month quota is used up. Wait retryAfterSeconds. |
UpstreamError | 502 | The flight data provider failed. Retry shortly. |
ServerError, UnexpectedStatusError | other | Quote requestId to support. |
ConnectionError | none | No answer at all; timedOut when the timeout ran out. |
import { BadRequestError, PaymentRequiredError, RateLimitError } from 'flightbyte';
try {
await client.subscriptions.create(params);
} catch (err) {
if (err instanceof BadRequestError && err.legs.length > 0) {
console.log('Pick a leg:', err.legs.map((leg) => leg.origin).join(', '));
} else if (err instanceof PaymentRequiredError) {
console.log(`No watched flights left (${err.code}) until ${err.resetsAt}`);
} else if (err instanceof RateLimitError) {
await new Promise((resolve) => setTimeout(resolve, (err.retryAfterSeconds ?? 5) * 1000));
} else {
throw err;
}
}client.lastRateLimit holds the minute, day and month windows from the latest response. Every status and code is in Errors.
Configuration
| Option | Default | Meaning |
|---|---|---|
apiKey | required | Your API key, sent as x-api-key. |
baseUrl | https://api.flightbyte.dev/v1 | Another API base URL, such as a local one. |
fetch | the global fetch | Your own, for proxies, logging or tests. |
timeoutMs | 30000 | Bounds each request, body included. 0 leaves it to your signal. |
userAgent | none | Put in front of flightbyte-node/<version> in the user-agent header. |
What the library guarantees
- The key stays on your server. A key or signing secret inside a browser or mobile app can be read out of it. Call FlightByte from your backend; flag images, from
countries.flagUrl, are the one thing that needs no key. - The key stays with the API. Only reads follow redirects, and only on the API's own origin.
- New values do not break old code. A phase, status or change type added later is still a valid string. The tests check every method and type against the API's OpenAPI document.
- Zero is not unknown. A delay of
0and no delay reading are different values.
Next
- Build a flight landed notification in Node.js, end to end.
- Webhooks: payload, change types and the retry schedule.
- Building a flight delay notification system.
- The same calls in Python, Go, Ruby and Dart, or all five side by side.
SDKs
The official FlightByte libraries for Node.js, Python, Go, Ruby and Dart, with install commands, a first lookup, a watched flight and a verified webhook in each.
Python SDK
The official FlightByte library for Python 3.10+. Look a flight up, watch it, and verify signed flight status webhooks in Flask, Django and FastAPI, on the standard library alone.