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.
| Language | Install | Registry | Source | Runs on |
|---|---|---|---|---|
| Node.js and TypeScript | npm install flightbyte | npm | flightbyte-node | Node 20.19+, Bun, Deno, Cloudflare Workers, Vercel Edge |
| Python | pip install flightbyte | PyPI | flightbyte-python | Python 3.10+ |
| Go | go get github.com/FlightByte-dev/flightbyte-go | pkg.go.dev | flightbyte-go | Go 1.23+ |
| Ruby | gem install flightbyte | RubyGems | flightbyte-ruby | Ruby 3.1+, Rails, Sinatra, any Rack app |
| Dart and Flutter | dart pub add flightbyte | pub.dev | flightbyte-dart | Dart 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 flightbytepnpm 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); // A11When 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 receiverThe 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:
| Status | Node.js, Python, Ruby | Go | Dart |
|---|---|---|---|
| 400 | BadRequestError, with the legs to choose from | ErrBadRequest | BadRequestException |
| 401 | AuthenticationError | ErrUnauthorized | AuthenticationException |
| 402 | PaymentRequiredError, with when the quota resets | ErrPaymentRequired | PaymentRequiredException |
| 404 | NotFoundError | ErrNotFound | NotFoundException |
| 429 | RateLimitError, with how long to wait | ErrRateLimited | RateLimitException |
| 5xx | ServerError, and UpstreamError for 502 | ErrServer, ErrUpstream | ServerException, 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
httpstohttp, is never followed with the key on it, and onlyGETandHEADfollow 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
unknownin 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.