Quickstart
v3.2Kestrel SDK gives you a typed client for the Kestrel flight-data API, with retries, streaming pagination and webhook verification built in. This guide takes you from an empty project to your first live flight query in about five minutes.
Install the SDK
The SDK ships as ES modules with types included and runs on Node 18+, Bun, Deno and edge runtimes. Install it with your package manager:
$ npm install @kestrel/sdk
Create a client
Create one client and reuse it. It holds a keep-alive connection pool, so creating a client per request adds roughly 40ms of TLS setup to every call.
import { KestrelClient } from "@kestrel/sdk"; export const kestrel = new KestrelClient({ apiKey: process.env.KESTREL_KEY, region: "eu",});Client options
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | process.env.KESTREL_KEY | Scoped key from the dashboard. |
| region | "us" | "eu" | "ap" | "us" | Data residency region for every request. |
| timeout | number | 10_000 | Per-request timeout in milliseconds. |
| retries | number | RetryPolicy | 3 | Retries with exponential backoff and jitter. |
| fetch | typeof fetch | globalThis.fetch | Bring your own fetch for tests or proxies. |
Make your first request
Every resource lives on the client. Methods return typed objects and throw typed errors, so your editor knows the shape of a Flight before you run anything.
import { kestrel } from "@/lib/kestrel"; export async function GET() { const flight = await kestrel.flights.get("KS2041"); return Response.json({ status: flight.status, gate: flight.departure.gate, eta: flight.arrival.estimated, });}The response for a delayed flight looks like this:
{ "status": "delayed", "gate": "B14", "eta": "2026-10-01T18:42:00Z"}Stream results
List methods return an async iterator that fetches the next page only when you need it. Break out of the loop and no further requests are made.
import { kestrel } from "@/lib/kestrel"; for await (const flight of kestrel.flights.list({ airport: "LIS", status: "delayed" })) { console.log(flight.number, flight.delayMinutes);}Handle errors
Network failures and 5xx responses are retried automatically. Anything that reaches your code is a subclass of KestrelError with a stable code you can switch on.
import { kestrel } from "@/lib/kestrel";import { RateLimitError } from "@kestrel/sdk"; try { await kestrel.flights.get("KS2041");} catch (err) { if (err instanceof RateLimitError) await wait(err.retryAfter); else throw err;}