The web api allows accessing and managing some of the web resources available in your Air Account thorugh a set of REST like endpoints. This page specifies them as well as how to access the API.
Release History:
- 2022/03/14 - Version 1.0 of the API made public
Resources:
- haversine.py - A python command line wrapper and client to interface with the web API from the command line, kindly developed and made available by David Edson.
For simplicity and at this stage, authentication is achieved through HTTP Basic Authentication. This means that the web service will request authentication credentials when these are needed using a dialog box with username and password on your browser. These are your Air Account username and password.
Credentials can also be included in calling the URL for scripting connectors. In fact, this is how it's meant to be used. One of such examples is curl, so an API call would look like this:
The waypoints set of endpoints allows you to access your custom waypoints, as well as creating new ones and updating or deleting existing ones.
A custom endpoint is an entity with the following fields:
Field | Type | Description |
id | STRING (7) | A unique custom waypoint ID made of letters and digits only. |
description | STRING (63) | A more descriptive name for the custom waypoint |
latitude | DOUBLE | The waypoint's latitude in decimal form |
longitude | DOUBLE | The waypoint's longitude in decimal form |
elevation | DOUBLE | Optional, may be NULL. The waypoint's elevation in feet MSL |
Reading custom waypoints points
Use this endpoint via GET to retrieve the list of custom waypoints in JSON format:
/webapi/waypoints
For example:
curl https://username:password@haversine.com/webapi/waypoints
Resulting in something like this:
{ "result": "success", "status_code": 200, "waypoints": [ { "id": "N5038", "description": "OCEAN POINT", "latitude": 50.231321, "longitude": -38.34243, "elevation": null }, { "id": "LHR", "description": "LONDON HEATHROW", "latitude": 51.4775, "longitude": -0.461389, "elevation": 83.0 } ] }
Creating a new waypoint
Use this endpoint via GET or POST to create a new custom waypoint in your account. The new waypoint will be beamed down to AirTrack instances when logged in.
/webapi/waypoints/new/:id
Pass parameters latitude and longitude at least and optionally a description and elevation in feet.
For example:
curl https://username:password@haversine.com/webapi/waypoints/new/WPT1?latitude=50&longitude=-30&elevation=35000&description=DESC
Resulting in something like this:
{ "result": "success", "status_code": 200, "description": "waypoint added successfully", "waypoint": { "id": "WPT1", "description": "DESC", "latitude": 50.0, "longitude": -30.0, "elevation": 35000.0 } }
And on error, on missing latitude and longitude:
{ "result": "fail", "status_code": 400, "errors": [ "missing latitude", "missing longitude" ] }
Updating a custom waypoint
Use this endpoint via GET or POST to update an existing waypoint in your account or creating a new one if it doesn't exist. The new waypoint will be beamed down to AirTrack instances when logged in.
/webapi/waypoints/update/:id
Pass parameters latitude and longitude at least and optionally a description and elevation in feet.
For example:
curl https://username:password@haversine.com/webapi/waypoints/update/WPT1?latitude=50.0&longitude=-40.0&elevation=35000&description=DESC
Resulting in something like this:
{ "result": "success", "status_code": 200, "description": "waypoint updated successfully", "waypoint": { "id": "WPT1", "description": "DESC", "latitude": 50.0, "longitude": -40.0, "elevation": 35000.0 } }
Deleting an existing custom waypoint
Use this endpoint via GET or POST to delete an existing waypoint from your account. The waypoint should be deleted from AirTrack instances when logged in.
/webapi/waypoints/delete/:id
For example:
curl https://username:password@haversine.com/webapi/waypoints/delete/WPT1
Resulting in something like this:
{ "result": "success", "status_code": 200, "description": "waypoint deleted successfully" }
The navdata set of endpoins allows you to query and select from available navdata sets. These sets are then used in the route section, containing a selection of Airports, FIXes, VORs, NDBs, Runways, Procedures, Airways and so forth that can be used for flight planning.
The FAA sets ones are available to all users as they are public, but only cover the United States.
There is one old Navigraph data set which is also available to all users as a default, but is significantly out-of-date.
Lastly there may be newer Navigraph datasets for selection if the user has a navigraph subscription and has downloaded the dataset at least once from Navigraph onto AirTrack while being logged in with an Air Account.
Please note: A data set selected here only reflects in the behaviour of route planning in the Routes section of the Air account. It does not select the cycle in AirTrack and this needs to be done manually there too in order for them to match.
Reading the available data sets
Use this endpoint via GET to retrieve the list of navdata sets available for selection in JSON format:
/webapi/navdata/sets
For example:
curl https://username:password@haversine.com/webapi/navdata/sets
Resulting in something like this:
{ "result": "success", "status_code": 200, "sets": [ { "id": "N2201", "cycle": "2201", "description": "NAVIGRAPH 2201", "period": "2022/1/27 - 2022/2/23", "selected": false, "status": "out-of-date" }, { "id": "N2202", "cycle": "2202", "description": "NAVIGRAPH 2202", "period": "2022/2/24 - 2022/3/23", "selected": true, "status": "current" }, { "id": "F2202", "cycle": "2202", "description": "FAA CIFP 2202 (US ONLY)", "period": "2022/2/24 - 2022/3/23", "selected": false, "status": "current" } ] }
Selecting a navdata set
Use this endpoint via GET or POST to select a navdata set in your account.
/webapi/navdata/select/:id
For example:
curl https://username:password@haversine.com/webapi/navdata/select/F2202
Resulting in something like this:
{ "result": "success", "status_code": 200, "description": "navdata set selected successfully" }
The routes set of endpoints allows you to access your custom routes or flight plans, as well as creating new ones and updating or deleting existing ones.
A route represents a path between two points, usually two airports although this isn't always the case (AirTrack allows the creation of flight plans in the FMC from any point type to any point type, so when these are used, a route may appear in this section which is not between airports). But for the majority of cases let us consider routes are between two airports.
A route comprises the following fields:
Field | Type | Description |
name | STRING (63) | A name for the route; it's unique key |
origin | STRING (7) | The name of the first waypoint; typically the airport's ICAO |
departure_runway | STRING (7) | May be NULL; otherwise the departire runway ID |
sid | STRING (15) | May be NULL or SID (departure) identifier |
path | STRING | May be NULL or empty, the sequence of points and airways along the route excluding procedures, runways and airports |
destination | STRING (7) | The destination waypoint ID, typically the airport's ICAO |
star | STRING (15) | May be NULL or STAR(arrival) identifier |
approach | STRING (15) | May be NULL or IAP (approach) identifier |
arrival_runway | STRING (7) | May be NULL; otherwise the arrival runway ID |
length | DOUBLE | The calculated route length, may be incorrect and/or not precise, ROM |
flight_level | INT | If specified (non NULL), the desired flight level in feet MSL, e.g. 35000 for FL350 |
climb_descent_tas | INT | If specified (non NULL), the climb and descent speed in knots of true air speed (TAS) |
vertical_speed_fpm | INT | If specified (non NULL), the climb and descent vertical speed in feet per minute, e.g. 1800 |
points | ROUTE POINT | A sequence of route points |
The last 3 fields, flight_level, climb_descent_tas and vertical_speed_fpm, may be omitted and are generaly ignored by AirTrack. But when specified together with the route generator, they are used to estimate the altitude for each of the route points and given parameters. They represent a very primitive flight planner and give only an estimate of the altitudes crossing each point if climb and descent were to be done linearly. In practice there would be restrictions such as initial climb, those imposed by procedures, ATC, Airways and thus forth, which are currently ignored by the planner.
A route then has a sequence of route point objects attached to it, representing the various actual points, including those found in the procedures and airways. While a route path should represent the correct route, this is not always the case as some points may be incorrect or may not exist in the current cycle and as such be discarded, so it is the sequence of route points that gets loaded onto AirTrack's FMC for example.
A route point is defined as:
Field | Type | Description |
id | STRING (7) | Point identifier |
type | STRING (7) | Point type |
latitude | DOUBLE | Latitude |
longitude | DOUBLE | Latitude |
elevation | DOUBLE | Elevation in feet MSL at which to cross or NULL (if unspecified) |
Point type can be one of:
Type | Description |
APT | Airport |
RW | Runway |
ILS | ILS or localizer |
VOR | VOR navaid |
NDB | Enroute or Terminal NDB |
FIX | Enroute or Terminal Waypoint |
LOC | Locality |
CWP | Custom Waypoint |
POS | Position, a set of coordinates |
Reading currently saved routes
Use this endpoint via GET to retrieve the list of routes that are saved in your account. These routes are directly downloaded onto AirTrack's FMC when logged in using cloud sync.
/webapi/routes
For example:
curl https://username:password@haversine.com/webapi/routes
Resulting in something like this:
{ "result": "success", "status_code": 200, "routes": [ { "name": "OSLO-STOCKHOLM", "origin": "ENGM", "destination": "ESSA", "departure_runway": "RW01R", "sid": "EVTO9B / RW01R", "path": "MASEV Z183 ELTOK", "star": "ELTO4T / RW26", "approach": "I26", "arrival_runway": "RW26", "length": 359.3759082679553, "flight_level": 20000, "climb_descent_tas": 300, "vertical_speed_fpm": 1800, "points": [ { "id": "ENGM", "type": "APT", "latitude": 60.20277778, "longitude": 11.08388889, "elevation": 681.0 }, { "id": "RW01R", "type": "RW", "latitude": 60.17575556, "longitude": 11.10778333, "elevation": 681.0 }, { "id": "GM440", "type": "FIX", "latitude": 60.22694444, "longitude": 11.31666667, "elevation": 3187.0 }, { "id": "GM441", "type": "FIX", "latitude": 60.15433333, "longitude": 11.35527778, "elevation": 4813..0 }, { "id": "GM514", "type": "FIX", "latitude": 60.09583333, "longitude": 11.19444444, "elevation": 6961.0 }, ... ] ... ] }
Obtaining route path suggestions
Use this endpoint via GET or POST to retrieve a list of possible suggetions for route paths between a pair of airports.
Frequently used route paths are routes people file online in virtual ATC networks such as VATSIM and IVAO. Whenever one of these is observed, it gets recorded together with the number of times it has been seen.
These route paths are entered by users and as such, may and are likely to contain errors. Many users file routes with SIDs and STARs attached, with points in invalid format, or with points that no longer exist. A route path appearing here is not guaranteed to be valid, but because the number of times it is seen is recorded, it is likely that routes with a higher seen_count are valid or at least nearly so.
The end point returns a list of route paths between two airports, if any exist, reverse sorted by number of uses, and up to a limit of 100
The paths can then be attempted decoded and used to create actual routes in the database.
/webapi/routes/frequent
For example:
curl https://username:password@haversine.com/webapi/routes/frequent?origin=EGLL&destination=EHAM
Resulting in something like this:
{ "result": "success", "status_code": 200, "origin": "EGLL", "destination": "EHAM", "paths": [ { "path": "BPK Q295 BRAIN M197 REDFA", "seen_count": 272, "last_seen": "2022-03-09T17:09:45.000Z" }, { "path": "BPK7F BPK Q295 BRAIN M197 REDFA REDFA1A", "seen_count": 135, "last_seen": "2022-03-12T13:03:33.000Z" }, { "path": "BPK5K BPK Q295 BRAIN M197 REDFA REDFA1A", "seen_count": 36, "last_seen": "2022-03-09T18:58:08.000Z" }, { "path": "BPK7F BPK Q295 BRAIN M197 REDFA REDF1A ", "seen_count": 27, "last_seen": "2021-12-15T02:10:05.000Z" }, { "path": "BPK7G BPK Q295 BRAIN M197 REDFA REDFA1A", "seen_count": 19, "last_seen": "2022-01-10T22:40:42.000Z" }, ... up to 100 ... ] }
Creating a route
Use this end point via GET or POST to create a new route which then gets downloaded onto AirTrack. The end point usage is relatively simple with form parameters.
/webapi/routes/new/:name
The route name is the unique key and is given in the URL as the last path component.
This endpoint then needs at least two parameters, namely origin and destination. These are generaly the ICAO codes for the departure and arrival airports, but could be any other kind of waypoint, including custom waypoints. Specifying just these two creates a direct route between the two points.
For example:
curl https://username:password@haversine.com/webapi/routes/update/R1?origin=BUSEN&destination=ODLIX"
The result is a success JSON message with the route object and its enpoints embedded. In the above example:
{ "result": "success", "status_code": 200, "description": "route created successfully", "route": { "name": "R1", "origin": "BUSEN", "destination": "ODLIX", "departure_runway": null, "sid": null, "path": null, "star": null, "approach": null, "arrival_runway": null, "length": 33.025737155920154, "flight_level": null, "climb_descent_tas": null, "vertical_speed_fpm": null, "points": [ { "id": "BUSEN", "type": "FIX", "latitude": 38.544999999999995, "longitude": -10.0, "elevation": null }, { "id": "ODLIX", "type": "FIX", "latitude": 38.678888888888885, "longitude": -9.317222222222222, "elevation": null } ] } }
For most of the times, origin and destination are airports. In this case departure_runway and arrival_runway runways can be used to specify specific runways, can be used to specify the actual runways, and sid, star and approach can be used to specificy specific procedures, valid for the corrresponding airports.
Procedures can usually be identified by their code, but in come cases the same procedure exists for different transition identifiers. In this case the procedure name can be completed by adding a forward slash and the transition identifier.
Lastly but most importantly is the path parameter. This contains the actual route path between origin and destination excluding departure and arrival procedures, as a sequence of waypoints and optional airways, separated by space. These can be any FIX, VOR, NDB, and even CWPs.
The following example illustrates the creation of a full route between EGLL London Heathrow and EHAM Amsterdam Schiphol, departing from runway RW27R, using SID BPK7F, arriving via STAR REDF1A and ILS approach I18C/SUGOL, landing on runway RW18C. The path is via BPK, taking airway Q295 to BRAIN and then taking airway M197 to REDFA.
curl https://username:password@haversine.com/webapi/routes/new/R1?origin=EGLL&departure_runway=RW27R&sid=BPK7F&star=REDF1A&destination=EHAM&approach=I18C%2FSUGOL&arrival_runway=RW18C &path=BPKQ295%20BRAIN%20M197%20REDFA
The result is as follows; note that the airways Q295 and M197 were expanded and the points inbetween transitions were added in the list of route points, namely, TOTRI MATCH and GASBA RATLO:
{ "result": "success", "status_code": 200, "description": "route added successfully", "route": { "name": "R1", "origin": "EGLL", "destination": "EHAM", "departure_runway": "RW27R", "sid": "BPK7F/RW27R", "path": "BPK Q295 BRAIN M197 REDFA", "star": "REDF1A", "approach": "I18C/SUGOL", "arrival_runway": "RW18C", "length": 249.4465058033871, "flight_level": null, "climb_descent_tas": null, "vertical_speed_fpm": null, "points": [ { "id": "EGLL", "type": "APT", "latitude": 51.4775, "longitude": -0.4613888888888889, "elevation": 83.0 }, { "id": "RW27R", "type": "RW", "latitude": 51.477675000000005, "longitude": -0.43328333333333335, "elevation": 83.0 }, { "id": "D268D", "type": "FIX", "latitude": 51.484405555555554, "longitude": -0.5730888888888889, "elevation": null }, { "id": "D278F", "type": "FIX", "latitude": 51.50163611111111, "longitude": -0.6248722222222223, "elevation": null }, { "id": "D305H", "type": "FIX", "latitude": 51.5654, "longitude": -0.6459416666666666, "elevation": null }, { "id": "D326H", "type": "FIX", "latitude": 51.59422222222222, "longitude": -0.5824472222222222, "elevation": null }, { "id": "CHT", "type": "NDB", "latitude": 51.62314444444444, "longitude": -0.518575, "elevation": null }, { "id": "BPK", "type": "VOR", "latitude": 51.749722222222225, "longitude": -0.10666666666666667, "elevation": null }, { "id": "TOTRI", "type": "FIX", "latitude": 51.775, "longitude": 0.19666666666666666, "elevation": null }, { "id": "MATCH", "type": "FIX", "latitude": 51.77916666666667, "longitude": 0.25, "elevation": null }, { "id": "BRAIN", "type": "FIX", "latitude": 51.81108611111111, "longitude": 0.6516666666666667, "elevation": null }, { "id": "GASBA", "type": "FIX", "latitude": 51.836111111111116, "longitude": 0.8147222222222222, "elevation": null }, { "id": "RATLO", "type": "FIX", "latitude": 51.99138888888889, "longitude": 1.6819444444444442, "elevation": null }, { "id": "REDFA", "type": "FIX", "latitude": 52.114586111111116, "longitude": 2.487947222222222, "elevation": null }, { "id": "SULUT", "type": "FIX", "latitude": 52.447925, "longitude": 3.421063888888889, "elevation": null }, { "id": "SUGOL", "type": "FIX", "latitude": 52.525555555555556, "longitude": 3.9672222222222224, "elevation": null }, { "id": "SPL", "type": "VOR", "latitude": 52.332144444444445, "longitude": 4.749883333333333, "elevation": null }, { "id": "OA", "type": "NDB", "latitude": 52.470241666666666, "longitude": 4.753272222222222, "elevation": null }, { "id": "EH623", "type": "FIX", "latitude": 52.51925, "longitude": 4.757361111111111, "elevation": null }, { "id": "EH625", "type": "FIX", "latitude": 52.486000000000004, "longitude": 4.754277777777777, "elevation": null }, { "id": "RW18C", "type": "RW", "latitude": 52.33139722222223, "longitude": 4.740030555555555, "elevation": -11.0 }, { "id": "EHAM", "type": "APT", "latitude": 52.308055555555555, "longitude": 4.764166666666667, "elevation": -11.0 } ] } }
If there is an error in the decoding, the API returns a 400 with an array of errors. Say you misspelled REDFA a in the path by REDFB. This would mean that REDFB could not be found and that the airway M197 could not be expanded:
{ "result": "fail", "status_code": 400, "errors": [ "unable to decode point M197", "unable to decode point REDFB" ] }
Note that the route was created with all elevations set to NULL because we didn't specify them. There are two ways in which we could specify these or approximations of these, either using the built in calculator by giving the extra parameters flight_level, climb_descent_tas and vertical_speed_fpm or individually. In the first case the API calculates the corrresponding elevations for a climb/descent at TAS/VVI and sets the corresponding elevation for each of the points along the route, first going up and then coming down. As mentioned before, this is not always ideal as there are restrictions in place, but it serves as an easy and quick way to create a simple route with vertical significance, and because it had already been implemented it's here for anyone wishing to use it.
As an alternative to this, it is also possible to specify individual elevations for each of the waypoints on the path. We do this by adding a forward slash to the waypoint followed by an elevation in feet (e.g. BPK/12000, BRAIN/20000, ...). This however is incompatible with the auto generated altitudes procedure, so either use one or the other.
Updating a route
This endpoint is almost identical to the previous creation endpoint with the only difference that it updates an already existing route. If the route doesn't exist it gets created and this endpoint performs exactly like the new endpoint.
Updating a route causes the route points to be regenerated from path so beware, if you speficied a procedure in the creation you need to specify a procedure in its update too in order not to lose it.
/webapi/routes/update/:name
For example:
curl https://username:password@haversine.com/webapi/routes/update/R1?origin=EGLL&destination=EHAM&path=BPK%20Q295%20BRAIN%20M197%20REDFA"
Deleting a route
Use this endpoint via GET or POST to delete an existing route from your account. The route should be deleted from AirTrack instances when logged in.
/webapi/routes/delete/:name
For example:
curl https://username:password@haversine.com/webapi/routes/delete/R1
Resulting in something like this:
{ "result": "success", "status_code": 200, "description": "route deleted successfully" }