flyitalyadsb 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flyitalyadsb-0.1.0/.gitignore +25 -0
- flyitalyadsb-0.1.0/LICENSE +21 -0
- flyitalyadsb-0.1.0/NOTICE +13 -0
- flyitalyadsb-0.1.0/PKG-INFO +198 -0
- flyitalyadsb-0.1.0/README.md +162 -0
- flyitalyadsb-0.1.0/pyproject.toml +77 -0
- flyitalyadsb-0.1.0/src/flyitalyadsb/__init__.py +84 -0
- flyitalyadsb-0.1.0/src/flyitalyadsb/_version.py +1 -0
- flyitalyadsb-0.1.0/src/flyitalyadsb/client.py +465 -0
- flyitalyadsb-0.1.0/src/flyitalyadsb/errors.py +168 -0
- flyitalyadsb-0.1.0/src/flyitalyadsb/models.py +561 -0
- flyitalyadsb-0.1.0/src/flyitalyadsb/py.typed +0 -0
- flyitalyadsb-0.1.0/tests/conftest.py +89 -0
- flyitalyadsb-0.1.0/tests/test_client.py +420 -0
- flyitalyadsb-0.1.0/tests/test_live.py +27 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Your API key never goes in git. Keep it in an environment variable or in one of these files.
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
*.key
|
|
6
|
+
api-key.txt
|
|
7
|
+
examples/esp32/planes-overhead/secrets.h
|
|
8
|
+
|
|
9
|
+
# Python
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
.venv/
|
|
13
|
+
dist/
|
|
14
|
+
|
|
15
|
+
# Node
|
|
16
|
+
node_modules/
|
|
17
|
+
|
|
18
|
+
# Arduino / PlatformIO builds
|
|
19
|
+
build/
|
|
20
|
+
.pio/
|
|
21
|
+
|
|
22
|
+
# Editors and OS
|
|
23
|
+
.vscode/
|
|
24
|
+
.idea/
|
|
25
|
+
.DS_Store
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nesso Labs S.r.l.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Code and data are licensed separately.
|
|
2
|
+
|
|
3
|
+
The code of this package (flyitalyadsb, the Python client) is MIT licensed:
|
|
4
|
+
see LICENSE.
|
|
5
|
+
|
|
6
|
+
The flight data the API returns is NOT covered by the MIT licence. It is
|
|
7
|
+
published under Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0)
|
|
8
|
+
and served under the API terms of service:
|
|
9
|
+
https://flyitalyadsb.com/en/terms/
|
|
10
|
+
|
|
11
|
+
Credit it where your users see the data:
|
|
12
|
+
|
|
13
|
+
Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flyitalyadsb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client for the FlyItalyADSB ADS-B API: live aircraft positions worldwide, history, overflights and events. Commercial use on every plan, Free included.
|
|
5
|
+
Project-URL: Homepage, https://flyitalyadsb.com/en/data/api/
|
|
6
|
+
Project-URL: Documentation, https://flyitalyadsb.com/en/data/api/docs/
|
|
7
|
+
Project-URL: Source, https://github.com/flyitalyadsb/adsb-api/tree/main/python
|
|
8
|
+
Project-URL: Issues, https://github.com/flyitalyadsb/adsb-api/issues
|
|
9
|
+
Project-URL: Plans and pricing, https://flyitalyadsb.com/en/data/api/#piani
|
|
10
|
+
Project-URL: MCP server, https://flyitalyadsb.com/en/data/mcp/
|
|
11
|
+
Project-URL: OpenAPI, https://flyitalyadsb.com/openapi.json
|
|
12
|
+
Author-email: FlyItalyADSB <info@flyitalyadsb.com>
|
|
13
|
+
License-Expression: MIT
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
License-File: NOTICE
|
|
16
|
+
Keywords: ads-b,adsb,aircraft,aircraft tracking,api client,aviation,flight data,flight tracking,mcp,military aircraft,mlat,mode-s,squawk
|
|
17
|
+
Classifier: Development Status :: 4 - Beta
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: Intended Audience :: Science/Research
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
30
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
31
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
32
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
33
|
+
Classifier: Typing :: Typed
|
|
34
|
+
Requires-Python: >=3.9
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# flyitalyadsb: official Python client for the FlyItalyADSB ADS-B API
|
|
38
|
+
|
|
39
|
+
**flyitalyadsb** is the official Python client for the [FlyItalyADSB](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client) ADS-B API: live and historical aircraft positions as JSON for any point on Earth, from a community network of about 3,200 ADS-B and MLAT receivers. Commercial use is allowed on every plan, Free included. The Free key is self-serve and answers up to 500 km around a point; the Pro plan (€49/month) returns the whole world in one request. The data is unfiltered: military, PIA and LADD aircraft are flagged, not removed, and the network's own MLAT locates aircraft that don't broadcast a position. Beyond live positions there are per-aircraft history, overflights of a place, notable-traffic events and an MCP server for AI assistants. Standard library only (no dependencies), fully typed, Python 3.9+.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install flyitalyadsb
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quickstart
|
|
46
|
+
|
|
47
|
+
Get a free key with your email on the [API page](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client#api-key) (no approval step), then:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from flyitalyadsb import Client
|
|
51
|
+
|
|
52
|
+
client = Client() # reads the key from FLYITALYADSB_API_KEY, or Client(api_key="...")
|
|
53
|
+
|
|
54
|
+
# Every aircraft within 25 km of London Heathrow, right now
|
|
55
|
+
for a in client.near(51.47, -0.45, 25):
|
|
56
|
+
print(a.callsign, a.registration, a.icao_type, a.altitude, "MIL" if a.military else "")
|
|
57
|
+
|
|
58
|
+
print(client.limits) # your plan and usage this month, from the X-FIA-* headers
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Keep the key out of your code and out of git: an environment variable, or your secret store.
|
|
62
|
+
|
|
63
|
+
## Methods
|
|
64
|
+
|
|
65
|
+
Every method is one request on your key; the account calls through `request()` (`/me/location`, `/webhooks`) are not counted. Radii are in kilometres.
|
|
66
|
+
|
|
67
|
+
| Method | Endpoint | Returns |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| `near(lat, lon, radius_km)` | `/lat/{lat}/lon/{lon}/dist/{km}` | `AircraftList`: every aircraft within the radius, anywhere on Earth |
|
|
70
|
+
| `world()` | `/lat/0/lon/0/dist/20040` | `AircraftList`: the whole world in one request (Pro and Business plans) |
|
|
71
|
+
| `by_icao(icao)` | `/icao/{hex}` | `Aircraft`, or `None` if it isn't seen now |
|
|
72
|
+
| `by_callsign(callsign)` | `/callsign/{callsign}` | `Aircraft` or `None` |
|
|
73
|
+
| `by_registration(registration)` | `/reg/{reg}` | `Aircraft` or `None` |
|
|
74
|
+
| `military()`, `pia()`, `ladd()` | `/mil`, `/pia`, `/ladd` | `AircraftList`: military, PIA and LADD aircraft seen now, network-wide |
|
|
75
|
+
| `squawk(code)` | `/sqk/{squawk}` | `AircraftList`: e.g. `7700`, `7600`, `7500`, network-wide |
|
|
76
|
+
| `aircraft_type(designator)` | `/type/{type}` | `AircraftList`: an ICAO type, e.g. `"A320"`, `"B738"`, `"EC35"` |
|
|
77
|
+
| `history(icao)` | `/history/{icao}` | `HistoryDates`: the UTC days with a track |
|
|
78
|
+
| `history(icao, day)` | `/history/{icao}/{date}` | `Trace` or `None`: one day's track, `positions()` for the points |
|
|
79
|
+
| `profile(icao)` | `/profile/{icao}` | `Profile` or `None`: identity, live status, history summary, links |
|
|
80
|
+
| `overflights(lat, lon, radius_km, start, end)` | `/overflights` | `Overflights`: the aircraft that flew over a place between two times |
|
|
81
|
+
| `events(lat, lon, radius_km, since=, until=, kinds=)` | `/events` | `Events`: emergencies, military and other notable traffic, up to 7 days back |
|
|
82
|
+
| `request(method, path, params=, body=)` | any other, e.g. `/me/location`, `/webhooks` | the parsed JSON |
|
|
83
|
+
| `request_key(email, found_via="pypi")` (a function) | `POST /keys` | asks for a free key: the address gets a one-time link. Never called for you |
|
|
84
|
+
|
|
85
|
+
`Aircraft` has typed fields with readable names (`callsign`, `registration`, `icao_type`, `lat`, `lon`, `altitude` in feet or `"ground"`, `ground_speed` in knots, `vertical_rate` in ft/min, `squawk`, `source` such as `adsb_icao` or `mlat`, `db_flags`) and the flags `military`, `interesting`, `pia`, `ladd`, `on_ground` and `from_mlat`. Every field the API sent stays available with its own name in `raw` and through `get()`, e.g. `a.get("nav_altitude_mcp")`. Lists are iterable and have `len()`. Every result keeps the full JSON in `raw`. The fields and units: [fields and units](https://flyitalyadsb.com/en/data/api/docs/fields/?utm_source=pypi&utm_campaign=python-client).
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from datetime import datetime, timedelta, timezone
|
|
89
|
+
|
|
90
|
+
now = datetime.now(timezone.utc)
|
|
91
|
+
|
|
92
|
+
# What flew within 3 km of a place in the last 2 hours, with the lowest altitude in the circle
|
|
93
|
+
for o in client.overflights(45.4642, 9.19, 3, now - timedelta(hours=2), now):
|
|
94
|
+
print(o.closest_time, o.registration, o.icao_type, o.callsigns, o.min_alt_ft, o.closest_km)
|
|
95
|
+
|
|
96
|
+
# Emergencies and military traffic within 100 km in the last 24 hours
|
|
97
|
+
for e in client.events(45.54, 10.22, 100, kinds=["emergency", "military"]):
|
|
98
|
+
print(e.time, e.kind, e.reason, e.callsign, e.registration, e.map_url)
|
|
99
|
+
|
|
100
|
+
# One aircraft's days with a track, and its last day's track
|
|
101
|
+
dates = client.history("4ca7b5")
|
|
102
|
+
if dates.dates:
|
|
103
|
+
track = client.history("4ca7b5", dates.dates[-1])
|
|
104
|
+
print(len(track.positions()) if track else 0, "points")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Plans and limits
|
|
108
|
+
|
|
109
|
+
Choose mostly by area: each request asks for the aircraft in a circle, and the largest circle depends on the plan. Commercial use is allowed on every plan, Free included.
|
|
110
|
+
|
|
111
|
+
| Plan | Price per month (before tax) | Requests/min (per key) | Requests/month | Radius per request | Overflights |
|
|
112
|
+
| --- | --- | --- | --- | --- | --- |
|
|
113
|
+
| Free | €0 | 30 | 300,000 | up to 500 km | 10 km, 6 h window |
|
|
114
|
+
| Starter | €9 | 60 | 1,000,000 | up to 1,000 km | 25 km, 24 h |
|
|
115
|
+
| Pro | €49 | 300 | 10,000,000 | whole world | 50 km, 24 h |
|
|
116
|
+
| Business | €249 | 1,000 | 50,000,000 | whole world | 50 km, 24 h |
|
|
117
|
+
|
|
118
|
+
- The Free plan also has a cap of 100 requests a minute per IP.
|
|
119
|
+
- A paid plan raises the limits of the key you already have.
|
|
120
|
+
- Requests refused for a limit are not counted, and nothing is ever billed beyond the plan.
|
|
121
|
+
- The monthly counter resets on the 1st. No plan includes an SLA: the service is best effort.
|
|
122
|
+
- Current prices and limits are always on the [plans page](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client#piani).
|
|
123
|
+
|
|
124
|
+
`client.limits` (and `.limits` on every result) reports the key's state from the `X-FIA-Plan`, `X-FIA-Limit-Per-Min`, `X-FIA-Quota-Month` and `X-FIA-Used-Month` headers: `plan`, `limit_per_min`, `quota_month`, `used_month` and `remaining_month`.
|
|
125
|
+
|
|
126
|
+
## Errors
|
|
127
|
+
|
|
128
|
+
| Exception | When | Useful attributes |
|
|
129
|
+
| --- | --- | --- |
|
|
130
|
+
| `PlanLimitError` | 403 or 429: a limit of the plan | `reason` (`"radius"`, `"overflights"`, `"paid_plan"`, `"rate_limit"`, `"monthly_quota"`), `max_radius_km`, `retry_after`, `resets`, `plans_url` |
|
|
131
|
+
| `AuthError` | 401: missing or invalid key | `help_url` |
|
|
132
|
+
| `NotFoundError` | 404 (the lookups return `None` instead) | |
|
|
133
|
+
| `ApiError` | any other error answer, e.g. 400 | `status`, `message`, `code`, `body`, `limits` |
|
|
134
|
+
| `TransportError` | no usable answer: network, timeout, not JSON | |
|
|
135
|
+
|
|
136
|
+
All of them are `FlyItalyADSBError`.
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from flyitalyadsb import Client, PlanLimitError
|
|
140
|
+
|
|
141
|
+
client = Client(user_agent="my-app/1.0") # name your app in the User-Agent
|
|
142
|
+
try:
|
|
143
|
+
everything = client.world()
|
|
144
|
+
except PlanLimitError as e:
|
|
145
|
+
if e.reason == "radius": # Free and Starter: 500 and 1,000 km per request
|
|
146
|
+
print(f"Up to {e.max_radius_km:g} km on this plan; the whole world needs Pro: {e.plans_url}")
|
|
147
|
+
elif e.reason == "monthly_quota":
|
|
148
|
+
print("Monthly quota used up until", e.resets, e.plans_url)
|
|
149
|
+
else:
|
|
150
|
+
print(e)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The client never hammers the API. On a 429 or 503 that carries `Retry-After` of at most `max_retry_wait` seconds (default 30), it waits once and tries again; otherwise it raises. Radius and monthly-quota errors are never retried. The timeout is 30 seconds by default (`Client(timeout=...)`).
|
|
154
|
+
|
|
155
|
+
## What's in the data
|
|
156
|
+
|
|
157
|
+
- One record per aircraft in readsb's aircraft.json format: ICAO address, position, altitude, speed, track, vertical rate, squawk, category, and the military, PIA and LADD flags. Registration and ICAO type are present for about 99% of aircraft, callsign for about 98%.
|
|
158
|
+
- Unfiltered: military, PIA and LADD aircraft are flagged, not hidden. Positions from ADS-B and from the network's own MLAT, which covers many military aircraft.
|
|
159
|
+
- The picture is rebuilt every 2 seconds. Coverage follows the receivers, worldwide: check an area with the [coverage tool](https://flyitalyadsb.com/en/data/coverage/?utm_source=pypi&utm_campaign=python-client) before you build on it.
|
|
160
|
+
- History: per-aircraft daily tracks for every day since 2026-08-17, plus 2022 to 2024 with gaps. Overflights of a place since 2026-08-17.
|
|
161
|
+
- Not included: routes (departure and arrival airports), schedules and photos.
|
|
162
|
+
|
|
163
|
+
## Licence and credit
|
|
164
|
+
|
|
165
|
+
The flight data is licensed [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). The only thing asked is a credit with the licence where your users see the data (in the app, on the device or in its manual, on the product page), with a link to flyitalyadsb.com:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The same line is `flyitalyadsb.ATTRIBUTION`. Share-alike covers the data and adapted versions of it (a dataset, feed or API built from it), not your product's code, artwork or design. Details: [using the data in a product](https://flyitalyadsb.com/en/data/products/using-the-data/?utm_source=pypi&utm_campaign=python-client) and the [terms of service](https://flyitalyadsb.com/en/terms/?utm_source=pypi&utm_campaign=python-client).
|
|
172
|
+
|
|
173
|
+
The code of this package is [MIT](https://github.com/flyitalyadsb/adsb-api/blob/main/python/LICENSE); the data it returns is not MIT (see [NOTICE](https://github.com/flyitalyadsb/adsb-api/blob/main/python/NOTICE)).
|
|
174
|
+
|
|
175
|
+
## MCP server for AI assistants
|
|
176
|
+
|
|
177
|
+
The same data, with the same key, is available to AI assistants through an MCP server at `https://flyitalyadsb.com/mcp` (Streamable HTTP, listed in the official MCP registry as `com.flyitalyadsb/mcp`). On claude.ai: Connectors, Add custom connector, URL `https://flyitalyadsb.com/mcp`. In Claude Code:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
claude mcp add --transport http flyitalyadsb https://flyitalyadsb.com/mcp \
|
|
181
|
+
--header "X-Api-Key: $FLYITALYADSB_API_KEY"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Guide: [MCP and AI agents](https://flyitalyadsb.com/en/data/mcp/?utm_source=pypi&utm_campaign=python-client).
|
|
185
|
+
|
|
186
|
+
## Links
|
|
187
|
+
|
|
188
|
+
- [API page: plans and a free key](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client)
|
|
189
|
+
- [API documentation](https://flyitalyadsb.com/en/data/api/docs/?utm_source=pypi&utm_campaign=python-client): [endpoints](https://flyitalyadsb.com/en/data/api/docs/endpoints/?utm_source=pypi&utm_campaign=python-client), [limits and errors](https://flyitalyadsb.com/en/data/api/docs/limits-and-errors/?utm_source=pypi&utm_campaign=python-client), [history](https://flyitalyadsb.com/en/data/api/docs/history/?utm_source=pypi&utm_campaign=python-client), [alerts and webhooks](https://flyitalyadsb.com/en/data/api/docs/alerts/?utm_source=pypi&utm_campaign=python-client), [commercial use](https://flyitalyadsb.com/en/data/api/docs/commercial-use/?utm_source=pypi&utm_campaign=python-client)
|
|
190
|
+
- [OpenAPI 3.1 spec](https://flyitalyadsb.com/openapi.json)
|
|
191
|
+
- [Examples and source on GitHub](https://github.com/flyitalyadsb/adsb-api) (curl, Python, Node.js, ESP32)
|
|
192
|
+
- [Service status](https://flyitalyadsb.com/en/status/?utm_source=pypi&utm_campaign=python-client) · [Contact](https://flyitalyadsb.com/en/contact/?utm_source=pypi&utm_campaign=python-client)
|
|
193
|
+
|
|
194
|
+
Found a bug in the client? [Open an issue](https://github.com/flyitalyadsb/adsb-api/issues).
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0. Service provided by Nesso Labs S.r.l.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# flyitalyadsb: official Python client for the FlyItalyADSB ADS-B API
|
|
2
|
+
|
|
3
|
+
**flyitalyadsb** is the official Python client for the [FlyItalyADSB](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client) ADS-B API: live and historical aircraft positions as JSON for any point on Earth, from a community network of about 3,200 ADS-B and MLAT receivers. Commercial use is allowed on every plan, Free included. The Free key is self-serve and answers up to 500 km around a point; the Pro plan (€49/month) returns the whole world in one request. The data is unfiltered: military, PIA and LADD aircraft are flagged, not removed, and the network's own MLAT locates aircraft that don't broadcast a position. Beyond live positions there are per-aircraft history, overflights of a place, notable-traffic events and an MCP server for AI assistants. Standard library only (no dependencies), fully typed, Python 3.9+.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install flyitalyadsb
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Quickstart
|
|
10
|
+
|
|
11
|
+
Get a free key with your email on the [API page](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client#api-key) (no approval step), then:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from flyitalyadsb import Client
|
|
15
|
+
|
|
16
|
+
client = Client() # reads the key from FLYITALYADSB_API_KEY, or Client(api_key="...")
|
|
17
|
+
|
|
18
|
+
# Every aircraft within 25 km of London Heathrow, right now
|
|
19
|
+
for a in client.near(51.47, -0.45, 25):
|
|
20
|
+
print(a.callsign, a.registration, a.icao_type, a.altitude, "MIL" if a.military else "")
|
|
21
|
+
|
|
22
|
+
print(client.limits) # your plan and usage this month, from the X-FIA-* headers
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Keep the key out of your code and out of git: an environment variable, or your secret store.
|
|
26
|
+
|
|
27
|
+
## Methods
|
|
28
|
+
|
|
29
|
+
Every method is one request on your key; the account calls through `request()` (`/me/location`, `/webhooks`) are not counted. Radii are in kilometres.
|
|
30
|
+
|
|
31
|
+
| Method | Endpoint | Returns |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| `near(lat, lon, radius_km)` | `/lat/{lat}/lon/{lon}/dist/{km}` | `AircraftList`: every aircraft within the radius, anywhere on Earth |
|
|
34
|
+
| `world()` | `/lat/0/lon/0/dist/20040` | `AircraftList`: the whole world in one request (Pro and Business plans) |
|
|
35
|
+
| `by_icao(icao)` | `/icao/{hex}` | `Aircraft`, or `None` if it isn't seen now |
|
|
36
|
+
| `by_callsign(callsign)` | `/callsign/{callsign}` | `Aircraft` or `None` |
|
|
37
|
+
| `by_registration(registration)` | `/reg/{reg}` | `Aircraft` or `None` |
|
|
38
|
+
| `military()`, `pia()`, `ladd()` | `/mil`, `/pia`, `/ladd` | `AircraftList`: military, PIA and LADD aircraft seen now, network-wide |
|
|
39
|
+
| `squawk(code)` | `/sqk/{squawk}` | `AircraftList`: e.g. `7700`, `7600`, `7500`, network-wide |
|
|
40
|
+
| `aircraft_type(designator)` | `/type/{type}` | `AircraftList`: an ICAO type, e.g. `"A320"`, `"B738"`, `"EC35"` |
|
|
41
|
+
| `history(icao)` | `/history/{icao}` | `HistoryDates`: the UTC days with a track |
|
|
42
|
+
| `history(icao, day)` | `/history/{icao}/{date}` | `Trace` or `None`: one day's track, `positions()` for the points |
|
|
43
|
+
| `profile(icao)` | `/profile/{icao}` | `Profile` or `None`: identity, live status, history summary, links |
|
|
44
|
+
| `overflights(lat, lon, radius_km, start, end)` | `/overflights` | `Overflights`: the aircraft that flew over a place between two times |
|
|
45
|
+
| `events(lat, lon, radius_km, since=, until=, kinds=)` | `/events` | `Events`: emergencies, military and other notable traffic, up to 7 days back |
|
|
46
|
+
| `request(method, path, params=, body=)` | any other, e.g. `/me/location`, `/webhooks` | the parsed JSON |
|
|
47
|
+
| `request_key(email, found_via="pypi")` (a function) | `POST /keys` | asks for a free key: the address gets a one-time link. Never called for you |
|
|
48
|
+
|
|
49
|
+
`Aircraft` has typed fields with readable names (`callsign`, `registration`, `icao_type`, `lat`, `lon`, `altitude` in feet or `"ground"`, `ground_speed` in knots, `vertical_rate` in ft/min, `squawk`, `source` such as `adsb_icao` or `mlat`, `db_flags`) and the flags `military`, `interesting`, `pia`, `ladd`, `on_ground` and `from_mlat`. Every field the API sent stays available with its own name in `raw` and through `get()`, e.g. `a.get("nav_altitude_mcp")`. Lists are iterable and have `len()`. Every result keeps the full JSON in `raw`. The fields and units: [fields and units](https://flyitalyadsb.com/en/data/api/docs/fields/?utm_source=pypi&utm_campaign=python-client).
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from datetime import datetime, timedelta, timezone
|
|
53
|
+
|
|
54
|
+
now = datetime.now(timezone.utc)
|
|
55
|
+
|
|
56
|
+
# What flew within 3 km of a place in the last 2 hours, with the lowest altitude in the circle
|
|
57
|
+
for o in client.overflights(45.4642, 9.19, 3, now - timedelta(hours=2), now):
|
|
58
|
+
print(o.closest_time, o.registration, o.icao_type, o.callsigns, o.min_alt_ft, o.closest_km)
|
|
59
|
+
|
|
60
|
+
# Emergencies and military traffic within 100 km in the last 24 hours
|
|
61
|
+
for e in client.events(45.54, 10.22, 100, kinds=["emergency", "military"]):
|
|
62
|
+
print(e.time, e.kind, e.reason, e.callsign, e.registration, e.map_url)
|
|
63
|
+
|
|
64
|
+
# One aircraft's days with a track, and its last day's track
|
|
65
|
+
dates = client.history("4ca7b5")
|
|
66
|
+
if dates.dates:
|
|
67
|
+
track = client.history("4ca7b5", dates.dates[-1])
|
|
68
|
+
print(len(track.positions()) if track else 0, "points")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Plans and limits
|
|
72
|
+
|
|
73
|
+
Choose mostly by area: each request asks for the aircraft in a circle, and the largest circle depends on the plan. Commercial use is allowed on every plan, Free included.
|
|
74
|
+
|
|
75
|
+
| Plan | Price per month (before tax) | Requests/min (per key) | Requests/month | Radius per request | Overflights |
|
|
76
|
+
| --- | --- | --- | --- | --- | --- |
|
|
77
|
+
| Free | €0 | 30 | 300,000 | up to 500 km | 10 km, 6 h window |
|
|
78
|
+
| Starter | €9 | 60 | 1,000,000 | up to 1,000 km | 25 km, 24 h |
|
|
79
|
+
| Pro | €49 | 300 | 10,000,000 | whole world | 50 km, 24 h |
|
|
80
|
+
| Business | €249 | 1,000 | 50,000,000 | whole world | 50 km, 24 h |
|
|
81
|
+
|
|
82
|
+
- The Free plan also has a cap of 100 requests a minute per IP.
|
|
83
|
+
- A paid plan raises the limits of the key you already have.
|
|
84
|
+
- Requests refused for a limit are not counted, and nothing is ever billed beyond the plan.
|
|
85
|
+
- The monthly counter resets on the 1st. No plan includes an SLA: the service is best effort.
|
|
86
|
+
- Current prices and limits are always on the [plans page](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client#piani).
|
|
87
|
+
|
|
88
|
+
`client.limits` (and `.limits` on every result) reports the key's state from the `X-FIA-Plan`, `X-FIA-Limit-Per-Min`, `X-FIA-Quota-Month` and `X-FIA-Used-Month` headers: `plan`, `limit_per_min`, `quota_month`, `used_month` and `remaining_month`.
|
|
89
|
+
|
|
90
|
+
## Errors
|
|
91
|
+
|
|
92
|
+
| Exception | When | Useful attributes |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `PlanLimitError` | 403 or 429: a limit of the plan | `reason` (`"radius"`, `"overflights"`, `"paid_plan"`, `"rate_limit"`, `"monthly_quota"`), `max_radius_km`, `retry_after`, `resets`, `plans_url` |
|
|
95
|
+
| `AuthError` | 401: missing or invalid key | `help_url` |
|
|
96
|
+
| `NotFoundError` | 404 (the lookups return `None` instead) | |
|
|
97
|
+
| `ApiError` | any other error answer, e.g. 400 | `status`, `message`, `code`, `body`, `limits` |
|
|
98
|
+
| `TransportError` | no usable answer: network, timeout, not JSON | |
|
|
99
|
+
|
|
100
|
+
All of them are `FlyItalyADSBError`.
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from flyitalyadsb import Client, PlanLimitError
|
|
104
|
+
|
|
105
|
+
client = Client(user_agent="my-app/1.0") # name your app in the User-Agent
|
|
106
|
+
try:
|
|
107
|
+
everything = client.world()
|
|
108
|
+
except PlanLimitError as e:
|
|
109
|
+
if e.reason == "radius": # Free and Starter: 500 and 1,000 km per request
|
|
110
|
+
print(f"Up to {e.max_radius_km:g} km on this plan; the whole world needs Pro: {e.plans_url}")
|
|
111
|
+
elif e.reason == "monthly_quota":
|
|
112
|
+
print("Monthly quota used up until", e.resets, e.plans_url)
|
|
113
|
+
else:
|
|
114
|
+
print(e)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The client never hammers the API. On a 429 or 503 that carries `Retry-After` of at most `max_retry_wait` seconds (default 30), it waits once and tries again; otherwise it raises. Radius and monthly-quota errors are never retried. The timeout is 30 seconds by default (`Client(timeout=...)`).
|
|
118
|
+
|
|
119
|
+
## What's in the data
|
|
120
|
+
|
|
121
|
+
- One record per aircraft in readsb's aircraft.json format: ICAO address, position, altitude, speed, track, vertical rate, squawk, category, and the military, PIA and LADD flags. Registration and ICAO type are present for about 99% of aircraft, callsign for about 98%.
|
|
122
|
+
- Unfiltered: military, PIA and LADD aircraft are flagged, not hidden. Positions from ADS-B and from the network's own MLAT, which covers many military aircraft.
|
|
123
|
+
- The picture is rebuilt every 2 seconds. Coverage follows the receivers, worldwide: check an area with the [coverage tool](https://flyitalyadsb.com/en/data/coverage/?utm_source=pypi&utm_campaign=python-client) before you build on it.
|
|
124
|
+
- History: per-aircraft daily tracks for every day since 2026-08-17, plus 2022 to 2024 with gaps. Overflights of a place since 2026-08-17.
|
|
125
|
+
- Not included: routes (departure and arrival airports), schedules and photos.
|
|
126
|
+
|
|
127
|
+
## Licence and credit
|
|
128
|
+
|
|
129
|
+
The flight data is licensed [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). The only thing asked is a credit with the licence where your users see the data (in the app, on the device or in its manual, on the product page), with a link to flyitalyadsb.com:
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The same line is `flyitalyadsb.ATTRIBUTION`. Share-alike covers the data and adapted versions of it (a dataset, feed or API built from it), not your product's code, artwork or design. Details: [using the data in a product](https://flyitalyadsb.com/en/data/products/using-the-data/?utm_source=pypi&utm_campaign=python-client) and the [terms of service](https://flyitalyadsb.com/en/terms/?utm_source=pypi&utm_campaign=python-client).
|
|
136
|
+
|
|
137
|
+
The code of this package is [MIT](https://github.com/flyitalyadsb/adsb-api/blob/main/python/LICENSE); the data it returns is not MIT (see [NOTICE](https://github.com/flyitalyadsb/adsb-api/blob/main/python/NOTICE)).
|
|
138
|
+
|
|
139
|
+
## MCP server for AI assistants
|
|
140
|
+
|
|
141
|
+
The same data, with the same key, is available to AI assistants through an MCP server at `https://flyitalyadsb.com/mcp` (Streamable HTTP, listed in the official MCP registry as `com.flyitalyadsb/mcp`). On claude.ai: Connectors, Add custom connector, URL `https://flyitalyadsb.com/mcp`. In Claude Code:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
claude mcp add --transport http flyitalyadsb https://flyitalyadsb.com/mcp \
|
|
145
|
+
--header "X-Api-Key: $FLYITALYADSB_API_KEY"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Guide: [MCP and AI agents](https://flyitalyadsb.com/en/data/mcp/?utm_source=pypi&utm_campaign=python-client).
|
|
149
|
+
|
|
150
|
+
## Links
|
|
151
|
+
|
|
152
|
+
- [API page: plans and a free key](https://flyitalyadsb.com/en/data/api/?utm_source=pypi&utm_campaign=python-client)
|
|
153
|
+
- [API documentation](https://flyitalyadsb.com/en/data/api/docs/?utm_source=pypi&utm_campaign=python-client): [endpoints](https://flyitalyadsb.com/en/data/api/docs/endpoints/?utm_source=pypi&utm_campaign=python-client), [limits and errors](https://flyitalyadsb.com/en/data/api/docs/limits-and-errors/?utm_source=pypi&utm_campaign=python-client), [history](https://flyitalyadsb.com/en/data/api/docs/history/?utm_source=pypi&utm_campaign=python-client), [alerts and webhooks](https://flyitalyadsb.com/en/data/api/docs/alerts/?utm_source=pypi&utm_campaign=python-client), [commercial use](https://flyitalyadsb.com/en/data/api/docs/commercial-use/?utm_source=pypi&utm_campaign=python-client)
|
|
154
|
+
- [OpenAPI 3.1 spec](https://flyitalyadsb.com/openapi.json)
|
|
155
|
+
- [Examples and source on GitHub](https://github.com/flyitalyadsb/adsb-api) (curl, Python, Node.js, ESP32)
|
|
156
|
+
- [Service status](https://flyitalyadsb.com/en/status/?utm_source=pypi&utm_campaign=python-client) · [Contact](https://flyitalyadsb.com/en/contact/?utm_source=pypi&utm_campaign=python-client)
|
|
157
|
+
|
|
158
|
+
Found a bug in the client? [Open an issue](https://github.com/flyitalyadsb/adsb-api/issues).
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0. Service provided by Nesso Labs S.r.l.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "flyitalyadsb"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Official Python client for the FlyItalyADSB ADS-B API: live aircraft positions worldwide, history, overflights and events. Commercial use on every plan, Free included."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE", "NOTICE"]
|
|
13
|
+
authors = [{ name = "FlyItalyADSB", email = "info@flyitalyadsb.com" }]
|
|
14
|
+
keywords = [
|
|
15
|
+
"ads-b",
|
|
16
|
+
"adsb",
|
|
17
|
+
"flight tracking",
|
|
18
|
+
"aviation",
|
|
19
|
+
"aircraft",
|
|
20
|
+
"mlat",
|
|
21
|
+
"api client",
|
|
22
|
+
"flight data",
|
|
23
|
+
"aircraft tracking",
|
|
24
|
+
"mode-s",
|
|
25
|
+
"military aircraft",
|
|
26
|
+
"squawk",
|
|
27
|
+
"mcp",
|
|
28
|
+
]
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 4 - Beta",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"Intended Audience :: Science/Research",
|
|
33
|
+
"Operating System :: OS Independent",
|
|
34
|
+
"Programming Language :: Python :: 3",
|
|
35
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
36
|
+
"Programming Language :: Python :: 3.9",
|
|
37
|
+
"Programming Language :: Python :: 3.10",
|
|
38
|
+
"Programming Language :: Python :: 3.11",
|
|
39
|
+
"Programming Language :: Python :: 3.12",
|
|
40
|
+
"Programming Language :: Python :: 3.13",
|
|
41
|
+
"Programming Language :: Python :: 3.14",
|
|
42
|
+
"Programming Language :: Python :: 3.15",
|
|
43
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
44
|
+
"Topic :: Scientific/Engineering :: GIS",
|
|
45
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
46
|
+
"Typing :: Typed",
|
|
47
|
+
]
|
|
48
|
+
dependencies = []
|
|
49
|
+
|
|
50
|
+
[project.urls]
|
|
51
|
+
Homepage = "https://flyitalyadsb.com/en/data/api/"
|
|
52
|
+
Documentation = "https://flyitalyadsb.com/en/data/api/docs/"
|
|
53
|
+
Source = "https://github.com/flyitalyadsb/adsb-api/tree/main/python"
|
|
54
|
+
Issues = "https://github.com/flyitalyadsb/adsb-api/issues"
|
|
55
|
+
"Plans and pricing" = "https://flyitalyadsb.com/en/data/api/#piani"
|
|
56
|
+
"MCP server" = "https://flyitalyadsb.com/en/data/mcp/"
|
|
57
|
+
OpenAPI = "https://flyitalyadsb.com/openapi.json"
|
|
58
|
+
|
|
59
|
+
[tool.hatch.version]
|
|
60
|
+
path = "src/flyitalyadsb/_version.py"
|
|
61
|
+
|
|
62
|
+
# Core metadata 2.4 (license expression and files) is all this package needs.
|
|
63
|
+
[tool.hatch.build.targets.wheel]
|
|
64
|
+
packages = ["src/flyitalyadsb"]
|
|
65
|
+
core-metadata-version = "2.4"
|
|
66
|
+
|
|
67
|
+
[tool.hatch.build.targets.sdist]
|
|
68
|
+
include = ["src/", "tests/", "README.md", "LICENSE", "NOTICE", "pyproject.toml"]
|
|
69
|
+
core-metadata-version = "2.4"
|
|
70
|
+
|
|
71
|
+
[tool.pytest.ini_options]
|
|
72
|
+
testpaths = ["tests"]
|
|
73
|
+
addopts = "-ra"
|
|
74
|
+
|
|
75
|
+
[tool.mypy]
|
|
76
|
+
strict = true
|
|
77
|
+
files = ["src"]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Official Python client for the FlyItalyADSB ADS-B API.
|
|
2
|
+
|
|
3
|
+
Live aircraft positions as JSON for any point on Earth, from a community network of
|
|
4
|
+
ADS-B and MLAT receivers, plus history, overflights and notable-traffic events.
|
|
5
|
+
Commercial use is allowed on every plan, Free included. Standard library only.
|
|
6
|
+
|
|
7
|
+
>>> from flyitalyadsb import Client
|
|
8
|
+
>>> client = Client() # reads FLYITALYADSB_API_KEY
|
|
9
|
+
>>> for a in client.near(51.47, -0.45, 25):
|
|
10
|
+
... print(a.callsign, a.registration, a.icao_type, a.altitude)
|
|
11
|
+
|
|
12
|
+
Docs: https://flyitalyadsb.com/en/data/api/docs/
|
|
13
|
+
Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from ._version import __version__
|
|
17
|
+
from .client import (
|
|
18
|
+
API_KEY_ENV,
|
|
19
|
+
BASE_URL,
|
|
20
|
+
SIGNUP_URL,
|
|
21
|
+
USER_AGENT,
|
|
22
|
+
WORLD_RADIUS_KM,
|
|
23
|
+
Client,
|
|
24
|
+
request_key,
|
|
25
|
+
)
|
|
26
|
+
from .errors import (
|
|
27
|
+
LIMITS_DOCS_URL,
|
|
28
|
+
PLANS_URL,
|
|
29
|
+
ApiError,
|
|
30
|
+
AuthError,
|
|
31
|
+
FlyItalyADSBError,
|
|
32
|
+
NotFoundError,
|
|
33
|
+
PlanLimitError,
|
|
34
|
+
TransportError,
|
|
35
|
+
)
|
|
36
|
+
from .models import (
|
|
37
|
+
Aircraft,
|
|
38
|
+
AircraftList,
|
|
39
|
+
Altitude,
|
|
40
|
+
Event,
|
|
41
|
+
Events,
|
|
42
|
+
HistoryDates,
|
|
43
|
+
Limits,
|
|
44
|
+
Overflight,
|
|
45
|
+
Overflights,
|
|
46
|
+
Profile,
|
|
47
|
+
Trace,
|
|
48
|
+
TracePoint,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
#: The credit the data's licence asks for, where your users see the data.
|
|
52
|
+
ATTRIBUTION = "Flight data: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0"
|
|
53
|
+
|
|
54
|
+
__all__ = [
|
|
55
|
+
"API_KEY_ENV",
|
|
56
|
+
"ATTRIBUTION",
|
|
57
|
+
"BASE_URL",
|
|
58
|
+
"LIMITS_DOCS_URL",
|
|
59
|
+
"PLANS_URL",
|
|
60
|
+
"SIGNUP_URL",
|
|
61
|
+
"USER_AGENT",
|
|
62
|
+
"WORLD_RADIUS_KM",
|
|
63
|
+
"Aircraft",
|
|
64
|
+
"AircraftList",
|
|
65
|
+
"Altitude",
|
|
66
|
+
"ApiError",
|
|
67
|
+
"AuthError",
|
|
68
|
+
"Client",
|
|
69
|
+
"Event",
|
|
70
|
+
"Events",
|
|
71
|
+
"FlyItalyADSBError",
|
|
72
|
+
"HistoryDates",
|
|
73
|
+
"Limits",
|
|
74
|
+
"NotFoundError",
|
|
75
|
+
"Overflight",
|
|
76
|
+
"Overflights",
|
|
77
|
+
"PlanLimitError",
|
|
78
|
+
"Profile",
|
|
79
|
+
"Trace",
|
|
80
|
+
"TracePoint",
|
|
81
|
+
"TransportError",
|
|
82
|
+
"__version__",
|
|
83
|
+
"request_key",
|
|
84
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|