FlightByte

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.

FlightByte has an official library for five languages. Each one wraps the whole API, types every response as the API sends it, turns error statuses into errors you can catch, and verifies webhook signatures against the raw body. All five are open source under the MIT license and versioned with semver from 1.0.0.

LanguageInstallRegistrySourceRuns on
Node.js and TypeScriptnpm install flightbytenpmflightbyte-nodeNode 20.19+, Bun, Deno, Cloudflare Workers, Vercel Edge
Pythonpip install flightbytePyPIflightbyte-pythonPython 3.10+
Gogo get github.com/FlightByte-dev/flightbyte-gopkg.go.devflightbyte-goGo 1.23+
Rubygem install flightbyteRubyGemsflightbyte-rubyRuby 3.1+, Rails, Sinatra, any Rack app
Dart and Flutterdart pub add flightbytepub.devflightbyte-dartDart 3.5+ servers and CLIs, and the backend behind a Flutter app

The Node.js, Python, Go and Ruby libraries have no dependencies outside the standard library. The Dart one depends on http and crypto.

Each library has a page of its own, with every install command, the receivers for its web frameworks, its error classes and its options: Node.js, Python, Go, Ruby and Dart. This page shows the five side by side.

Writing in another language? The API is plain HTTP and JSON: the Quickstart shows every call with curl, and the API reference is generated from the OpenAPI document.

Install

npm install flightbyte

pnpm add flightbyte, yarn add flightbyte, bun add flightbyte and deno add npm:flightbyte work too. The package ships ES modules and its own type definitions.

More on the Node.js SDK page, with receivers for Next.js, Hono, Workers, Bun, Deno and Express.

Look a flight up

Flights are addressed by airline code, flight number and the local departure date at the origin. The key comes from the dashboard; keep it in an environment variable.

import { FlightByte } from 'flightbyte';

const client = new FlightByte({ apiKey: process.env.FLIGHTBYTE_KEY! });

const flight = await client.flights.get({
  carrier: 'TK',
  flightNumber: '1848',
  date: '2026-09-12', // local departure date at the origin
});

console.log(flight.status.label);   // Scheduled
console.log(flight.departure.gate); // A11

When a flight number flies more than one leg that day, pass the origin airport (origin, or Origin in Go) to choose one. Without it the snapshot lists every leg in alternates; Flights → Leg selection has the details.

Watch a flight

A subscription watches one flight on one date and sends every change to your endpoint. The response carries the signing secret, shown in full only this once.

const created = await client.subscriptions.create(
  {
    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' },
  },
  { idempotencyKey: 'BK-1042' }, // safe to retry
);

const signingSecret = created.secret; // store it for your webhook receiver

The same resource has list, get, update, pause, resume, delete, sendTest, deliveries, events and rotateSecret, named in each language's own style. Listing every subscription page by page is one call: listAll in Node.js and Dart, list_all in Python and Ruby, the All iterator in Go.

Receive webhooks

Each library checks the x-flightbyte-signature header against the raw request body in constant time, rejects a timestamp more than five minutes off, and refuses an empty secret. Read the body as bytes, before any JSON parsing: a body that was parsed and serialised again no longer matches its signature.

Webhook.fetchHandler is a handler for any runtime with Request and Response: Next.js route handlers, Hono, Cloudflare Workers, Bun and Deno.

import { Webhook } from 'flightbyte';

const receive = Webhook.fetchHandler(process.env.FLIGHTBYTE_WEBHOOK_SECRET!, async (event) => {
  // A retry carries the same id: answer it, but don't handle it twice.
  if (!(await markHandled(event.id))) return;
  queue.push(event);
});

// Next.js App Router: app/api/flightbyte/route.ts
export const POST = receive;

With Express, take the raw body and call Webhook.constructEvent:

import express from 'express';
import { Webhook, WebhookSignatureError } from 'flightbyte';

app.post('/hooks/flights', 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);
  queue.push(event);
});

Answer with a 2xx within ten seconds and do the work afterwards, and deduplicate on the event id, since a retry carries the same one. Webhooks has the payload, the change types and the retry schedule.

Errors

A status of 400 and above becomes an error of its own class, carrying the API's error code, its message and the request id to quote to support. The ones most code handles:

StatusNode.js, Python, RubyGoDart
400BadRequestError, with the legs to choose fromErrBadRequestBadRequestException
401AuthenticationErrorErrUnauthorizedAuthenticationException
402PaymentRequiredError, with when the quota resetsErrPaymentRequiredPaymentRequiredException
404NotFoundErrorErrNotFoundNotFoundException
429RateLimitError, with how long to waitErrRateLimitedRateLimitException
5xxServerError, and UpstreamError for 502ErrServer, ErrUpstreamServerException, UpstreamException

In Go every API error is an *flightbyte.APIError that matches its sentinel with errors.Is. A request that never got an answer, from a timeout or a dropped connection, is a connection error in every library. The last response's X-RateLimit-* headers are on the client as lastRateLimit, last_rate_limit or LastRateLimit().

Errors lists every status and error code the API returns.

Safe by default

  • Your key stays with the API. A redirect to another host, or from https to http, is never followed with the key on it, and only GET and HEAD follow redirects at all.
  • Timeouts cover the whole request. A server that answers slowly, byte by byte, still runs into the limit.
  • An empty webhook secret is refused. Anyone can sign with an empty key, so it is an error rather than a key.
  • New values do not break decoding. A status or change type the API adds later comes through as its string, or as unknown in Dart, so an older library keeps working.

Each repository's README covers configuration (base URL, timeout, user agent, your own HTTP client), every method, and how the library is tested against the API's OpenAPI document.

On this page