API Documentation
Real-time aircraft positions with route data from TFMS flight plans, available via REST API and WebSocket feed.
Authentication
Every feeder gets a unique API key. Use it from any IP — your laptop, VPS, phone, scripts.
curl -H "Authorization: Bearer YOUR_API_KEY" https://adsbiq.com/api/v2/all
Your API key is shown on the join page and your feeder dashboard after install.
Alternative: IP-based auth (no key needed from home network)
Requests from your feeder's IP are automatically authenticated — no header needed:
curl https://adsbiq.com/api/v2/all
Not a feeder? Install in 60 seconds to get access.
Access & Rate Limits
All feeds (REST, WebSocket) are exclusively for active feeders. Non-feeders get 403. Become a feeder to get access.
| Feed | Limit |
|---|---|
| REST API | 60 req burst / 10 per minute sustained. Exceeding returns 429. |
| WebSocket | Server-push — no request rate limit. One connection per feeder. |
REST API
Request/response — poll for aircraft data on demand
Endpoints
/api/v2/all
Full aircraft snapshot — all currently tracked aircraft.
/api/v2/hex/{hex}
Single aircraft by ICAO 24-bit hex (e.g., ad5d5c).
/api/v2/reg/{reg}
Aircraft by registration (e.g., N960NK).
/api/v2/type/{type}
Aircraft by ICAO type designator (e.g., B738, A20N).
/api/v2/callsign/{callsign}
Aircraft by callsign (e.g., NKS3205).
/api/v2/lat/{lat}/lon/{lon}/dist/{nm}
Aircraft within radius (nautical miles). Example: /api/v2/lat/26.68/lon/-80.10/dist/50
/api/v2/squawk/{code}
Aircraft by squawk code (e.g., 7700).
/api/v2/signal
Real-time RSSI signal stats (no auth required). Returns avg, median, p10, p90, aircraft count.
/api/v2/signal/history
Last 5 minutes of signal readings (2s intervals, ~150 points). For chart priming.
/api/v2/stats
Lightweight network stats (no auth). Returns aircraft_count and messages.
Response Format
{
"now": 1774187176.0,
"messages": 6505606,
"total": 51,
"ctime": 1774187176.3,
"ptime": 1774187175.9,
"ac": [
{
"hex": "ad5d5c",
"type": "adsb_icao",
"flight": "NKS3205 ",
"category": "A3",
"squawk": "1770",
"emergency": "none",
"lat": 26.224091,
"lon": -80.960739,
"alt_baro": 33350,
"alt_geom": 34725,
"baro_rate": 1472,
"geom_rate": 1504,
"gs": 457.4,
"ias": 277,
"tas": 458,
"mach": 0.776,
"track": 2.26,
"track_rate": 0.0,
"roll": -0.7,
"mag_heading": 5.27,
"true_heading": 358.36,
"nav_qnh": 1012.8,
"nav_altitude_mcp": 35008,
"oat": -44,
"tat": -16,
"rssi": -23.1,
"messages": 1140,
"seen": 0.3,
"seen_pos": 0.98,
"r": "N960NK",
"t": "A20N",
"route_origin": "FLL",
"route_dest": "MCI"
}
]
}
Envelope
| Field | Description |
|---|---|
now | Unix epoch (UTC, 1dp) when readsb wrote this snapshot (feeder Pi clock) |
messages | Total ADS-B messages received since receiver start |
total | Number of aircraft in this response |
ctime | Unix epoch (UTC, 1dp) when the API server generated this response |
ptime | Unix epoch (UTC, 1dp) when the cache daemon last processed the data |
ADS-B Position & Flight Data
| Field | Type | Description |
|---|---|---|
hex | string | ICAO 24-bit address (lowercase hex) |
type | string | Source: adsb_icao, mlat, tisb, adsr |
flight | string | Callsign (8 chars, space-padded) |
r | string | Registration (e.g., N960NK) |
lat/lon | float | Position (WGS84 decimal degrees) |
alt_baro | int | "ground" | Barometric altitude (feet) or the string "ground" |
alt_geom | int | Geometric (GPS) altitude (feet) |
gs | float | Ground speed (knots) |
ias | int | Indicated airspeed (knots) |
tas | int | True airspeed (knots) |
mach | float | Mach number |
track | float | Track angle (degrees, 0=north) |
track_rate | float | Rate of turn (degrees/second) |
calc_track | float | Calculated track from position history |
roll | float | Roll angle (degrees, negative=left) |
mag_heading | float | Magnetic heading (degrees) |
true_heading | float | True heading (degrees) |
baro_rate | int | Barometric vertical rate (ft/min) |
geom_rate | int | Geometric vertical rate (ft/min) |
seen | float | Seconds since last message from this aircraft |
seen_pos | float | Seconds since last position update |
rssi | float | Signal strength (dBFS, typically -1 to -35) |
messages | int | Total messages received from this aircraft |
Navigation & Avionics
| Field | Type | Description |
|---|---|---|
squawk | string | Transponder squawk code |
emergency | string | Emergency status (none, general, downed, etc.) |
category | string | Emitter category (A1-A7, B1-B7, C1-C3) |
nav_qnh | float | Altimeter setting (hPa/mbar) |
nav_altitude_mcp | int | Selected altitude — MCP/FCU (feet) |
nav_altitude_fms | int | Selected altitude — FMS (feet) |
nav_heading | float | Selected heading (degrees) |
nav_modes | array | Active nav modes: autopilot, vnav, lnav, tcas, althold, approach |
alert | int | Alert flag (0 or 1) |
spi | int | Special Position Identification (0 or 1) |
nic | int | Navigation Integrity Category (0-11) |
rc | int | Containment radius (meters) |
nic_baro | int | NIC supplement for baro altitude |
nac_p | int | Navigation Accuracy — Position |
nac_v | int | Navigation Accuracy — Velocity |
sil | int | Source Integrity Level |
sil_type | string | SIL supplement: perhour or persample |
gva | int | Geometric Vertical Accuracy |
sda | int | System Design Assurance |
version | int | ADS-B version (0, 1, or 2) |
dbFlags | int | Bitmask: 1=military, 2=interesting, 4=PIA, 8=LADD |
mlat | array | Fields derived from multilateration |
tisb | array | Fields derived from TIS-B |
Meteorological (from aircraft avionics — BDS 4,4 / 4,5)
| Field | Type | Description |
|---|---|---|
oat | float | Outside air temperature (°C) |
tat | float | Total air temperature (°C) |
wd | int | Wind direction (degrees) |
ws | int | Wind speed (knots) |
Route (from TFMS flight plans)
| Field | Type | Description |
|---|---|---|
route_origin | string | Origin airport IATA code |
route_dest | string | Destination airport IATA code |
Compression
Send Accept-Encoding: gzip for ~80% smaller payloads.
curl -H "Accept-Encoding: gzip" --compressed https://adsbiq.com/api/v2/all
WebSocket Feed
Real-time push-based aircraft data — no polling needed
Connection
| Endpoint | wss://adsbiq.com/ws/ |
| Auth | IP-based (same as REST API) or Bearer token via query: wss://adsbiq.com/ws/?token=YOUR_API_KEY |
| Compression | permessage-deflate (negotiated automatically) |
| Ping/Pong | Server sends ping every 30s, timeout 10s |
| Max message size | 512 bytes (client → server) |
Channels
The WebSocket supports two channels on the same endpoint. Choose based on your use case:
| Channel | Interval | Coverage | How to connect |
|---|---|---|---|
| Global (default) | Every 10 seconds | All aircraft worldwide | wss://adsbiq.com/ws/ |
| Zone | Every 1 second | Aircraft within 250 nm of your location | wss://adsbiq.com/ws/?lat=40.7&lon=-74.0 |
Breaking change: The default (global) channel now updates every 10s instead of 1s.
If you need 1-second updates, switch to zone mode by adding ?lat=X&lon=Y to your connection URL.
Client Messages
Clients can switch channels mid-session by sending JSON messages:
| Action | Payload | Effect |
|---|---|---|
set_zone |
{"action": "set_zone", "lat": 40.7, "lon": -74.0} |
Switch to zone channel centered on (lat, lon). Triggers immediate full snapshot. |
set_global |
{"action": "set_global"} |
Switch back to global channel. Triggers full snapshot on next 10s tick. |
Message Types
The first message after connect is a full snapshot. Subsequent messages are deltas containing only changes. Every message includes a channel field ("global" or "zone").
Full Snapshot
{
"type": "full",
"channel": "zone",
"seq": 42,
"now": 1774187176.0,
"messages": 6505606,
"total": 51,
"ctime": 1774187176.3,
"ptime": 1774187175.9,
"ac": [ ... ]
}
Delta Update
{
"type": "delta",
"channel": "zone",
"seq": 43,
"now": 1774187177.0,
"messages": 6505620,
"total": 52,
"ctime": 1774187177.3,
"ptime": 1774187176.9,
"new": [
{"hex": "c99aab", "flight": "SWA789 ", "lat": 42.0, "lon": -72.0, "alt_baro": 30000, ...}
],
"update": [
{"hex": "ad5d5c", "lat": 26.3, "alt_baro": 34000}
],
"remove": ["a1b2c3"]
}
Delta Fields
| Field | Description |
|---|---|
type | "full" or "delta" |
channel | "global" or "zone" |
seq | Monotonic sequence number (increments by 1 per message, per channel). If your client sees a gap, reconnect to get a fresh full snapshot. |
total | Current aircraft count (zone = nearby count, global = worldwide). Clients SHOULD verify Object.keys(aircraft).length === msg.total after applying each delta — mismatch means state drift, reconnect. |
new | Full aircraft objects appearing for the first time (omitted if empty) |
update | Sparse objects: hex + only the fields that changed (omitted if empty) |
remove | Array of hex codes no longer tracked (omitted if empty) |
Client-Side Merge Pattern
update objects are sparse — they contain only hex plus fields that actually differ from the previous message. Merge them into your local state, do not replace:
// JavaScript — global channel (10s updates, all aircraft)
const ws = new WebSocket("wss://adsbiq.com/ws/");
// JavaScript — zone channel (1s updates, 250nm radius)
// const ws = new WebSocket("wss://adsbiq.com/ws/?lat=40.7&lon=-74.0");
const aircraft = {};
let lastSeq = 0;
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
// Sequence gap detection — reconnect if we missed a frame
if (msg.type === "delta" && msg.seq !== lastSeq + 1) {
ws.close(); // reconnect logic will get a fresh full
return;
}
lastSeq = msg.seq;
if (msg.type === "full") {
for (const k in aircraft) delete aircraft[k];
for (const ac of msg.ac) aircraft[ac.hex] = ac;
} else {
for (const ac of msg.new || []) aircraft[ac.hex] = ac;
for (const ac of msg.update || []) Object.assign(aircraft[ac.hex], ac);
for (const hex of msg.remove || []) delete aircraft[hex];
}
// Consistency check — total must match local state
if (Object.keys(aircraft).length !== msg.total) {
ws.close(); // state drift — reconnect for fresh full
}
};
// Switch to zone mid-session:
// ws.send(JSON.stringify({action: "set_zone", lat: 40.7, lon: -74.0}));
// Switch back to global:
// ws.send(JSON.stringify({action: "set_global"}));
Trigger Fields
Deltas are triggered by changes to: lat, lon, alt_baro, alt_geom, gs, ias, tas, mach, track, track_rate, roll, mag_heading, true_heading, baro_rate, geom_rate, squawk, emergency, flight, nav_qnh, nav_altitude_mcp, nav_altitude_fms, nav_heading, category, r, t, route_origin, route_dest.
Volatile fields (rssi, seen, seen_pos, messages) alone do not trigger an update, but are included in the sparse object if they changed alongside a trigger field.
Example Code
Get started quickly with a working Flask demo that queries every endpoint:
git clone https://github.com/adsbiq/adsbiq-api-demo.git
cd adsbiq-api-demo
pip install -r requirements.txt
python app.py
View on GitHub — includes REST and WebSocket examples.