Username: Password:

Air Web API

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.



Authentication

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:

curl https://username:password@haversine.com/webapi/endpoint


Waypoints

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:

FieldTypeDescription
idSTRING (7)A unique custom waypoint ID made of letters and digits only.
descriptionSTRING (63)A more descriptive name for the custom waypoint
latitudeDOUBLEThe waypoint's latitude in decimal form
longitudeDOUBLEThe waypoint's longitude in decimal form
elevationDOUBLEOptional, 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"
  }


NavData

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"
  }


Routes

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:

FieldTypeDescription
nameSTRING (63)A name for the route; it's unique key
originSTRING (7)The name of the first waypoint; typically the airport's ICAO
departure_runwaySTRING (7)May be NULL; otherwise the departire runway ID
sidSTRING (15)May be NULL or SID (departure) identifier
pathSTRINGMay be NULL or empty, the sequence of points and airways along the route excluding procedures, runways and airports
destinationSTRING (7)The destination waypoint ID, typically the airport's ICAO
starSTRING (15)May be NULL or STAR(arrival) identifier
approachSTRING (15)May be NULL or IAP (approach) identifier
arrival_runwaySTRING (7)May be NULL; otherwise the arrival runway ID
lengthDOUBLEThe calculated route length, may be incorrect and/or not precise, ROM
flight_levelINTIf specified (non NULL), the desired flight level in feet MSL, e.g. 35000 for FL350
climb_descent_tasINTIf specified (non NULL), the climb and descent speed in knots of true air speed (TAS)
vertical_speed_fpmINTIf specified (non NULL), the climb and descent vertical speed in feet per minute, e.g. 1800
pointsROUTE POINTA 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:

FieldTypeDescription
idSTRING (7)Point identifier
typeSTRING (7)Point type
latitudeDOUBLELatitude
longitudeDOUBLELatitude
elevationDOUBLEElevation in feet MSL at which to cross or NULL (if unspecified)

Point type can be one of:

TypeDescription
APTAirport
RWRunway
ILSILS or localizer
VORVOR navaid
NDBEnroute or Terminal NDB
FIXEnroute or Terminal Waypoint
LOCLocality
CWPCustom Waypoint
POSPosition, 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"
  }
© 2024 Haversine