shell javascript

Introduction

Welcome to the AirHub API! Our API powers the Business of Drones through the delivery of data and services to power and enrich your UAS applications.

The AirHub API is organized around REST. Our API has predictable resource-oriented URLs, accepts form-encoded or JSON request bodies, returns JSON-encoded responses and uses standard HTTP response codes, authentication, and verbs.

You can use the AirHub API in sandbox mode, which does not affect your live data or interact with production systems. The base URL you use to make requests determines whether the request is live mode or sandbox mode.

We have language examples in curl/Shell and JavaScript. You can view code examples in the dark area to the right, and switch the programming language with the tabs on the top right.

Request access to the API by sending an email to developers@airspacelink.com. We may wish to learn more about your use case before granting access.

Terms and Conditions

Non-commercial use of this API is governed by the Non-commercial AirHub for Business Terms & Conditions.

Support

Need help, or want to get in touch? You can contact support here.

Authentication

OAuth

To authorize, use this code:

# With shell, you can just pass the correct header with each request
curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'x-api-key: <your-subscription-key>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'client_secret=<your-client-secret>' \
--data-urlencode 'scope=<your-requested-scope> <second-scope>'
const params = {
  grant_type: "client_credentials",
  client_id: "<your-client-id>",
  client_secret: "<your-client-secret>",
  scope: "<your-requested-scope> <second-scope>",
};

const query = Object.keys(params)
  .map((key) => key + "=" + params[key])
  .join("&");

const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/oauth/token");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded", true);
xhr.setRequestHeader("x-api-key", "<your-subscription-key>", true);
xhr.send(query);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "status": 200,
  "message": "success",
  "data": {
    "accessToken": "xyz123",
    "expires": "2021-03-16T21:57:33.332Z",
    "scope": "advisory:read"
  }
}

AirHub uses client credentials and an API key to authenticate and authorize requests. Successful authentication will return an Oauth2 accessToken. AirHub expects the accessToken and x-api-key to be included in all subsequent API requests.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/oauth/token

Required Headers

Parameter Description
Content-Type application/x-www-form-urlencoded
x-api-key <your-api-key>

Form Encoded Parameters

Parameter Description
grant_type client_credentials
client_id Client id supplied to you by Airspace Link
client_secret Client secret supplied to you by Airspace Link
scope See available Oauth Scopes

Scopes

In addition to the Client ID and Secret, you must also supply one or many oauth scopes. If you're unfamiliar with scopes, you can think of them as bundles of related API endpoints that are authorized for access by your client application. Multiple scopes may be requested by separating each scope by a space.

Available Scopes

Scope Description
advisory:read Grants read access to our available advisories. This includes local and federal flight advisories.
aviation:read Grants read access to aviation facility map data.
hazar:read hazar is short for "Hazards and Risks". Grants read access to our hazar data.
operation:create Used for linking applications. Allows the creation of a UAS operation that can be linked into LAANC authorization app.
route:create Allows the creation of UAS waypoints that navigate around ground based hazards and risks.

Advisories

Advisories represent geographic areas where special consideration must be made before operating drones. Examples of advisories may range from restricted airspace - where it's illegal to operate a drone - to warnings where it's important for you to understand the context of where you're flying to maximize safety. Additional advisory types will be documented as they're added.

Query Advisories

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/advisory' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [-83.25923546832819,42.23958101718406],
        [-83.38626488727355,42.23958101718406],
        [-83.38626488727355,42.13782883968136],
        [-83.25923546832819,42.13782883968136],
        [-83.25923546832819,42.23958101718406]
      ]]
    },
    "category": "faa_107"
  }'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/advisory");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    geometry: {
      type: "Polygon",
      coordinates: [
        [
          [-83.25923546832819, 42.23958101718406],
          [-83.38626488727355, 42.23958101718406],
          [-83.38626488727355, 42.13782883968136],
          [-83.25923546832819, 42.13782883968136],
          [-83.25923546832819, 42.23958101718406],
        ],
      ],
    },
    category: "faa_107",
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this (dates and times are in UTC, and can be null):

{
  "data":
    [
      {
        "type": "Feature",
        "geometry": {"type": "Polygon", "coordinates": [[...]]},
        "properties": {
          "title": "4th of July Parade",
          "message": "Parade in downtown Springfield to celebrate ...",
          "severity": "warning",
          "advisorySource": "community",
          "advisoryType": "admin",
          "startDate": "2020-01-01", // UTC
          "startTime": "10:10", // military time
          "endDate": "2020-01-01", // UTC
          "endTime": "20:00", // military time
          "timezone": "America/New_York",
          "friendlyDayPhrase": "Active until further notice",
          "contactName": "John Doe",
          "contactPhone": "+12345678910",
          "contactEmail": "john@gov.gov",
          "contactUrl": "http://myadvisory.com/1234",
          "metadata": {
            // <custom attributes that may vary depending on the advisory>
          }
        }
      },
      {...},
      {...}
    ],
  "message": "success",
  "statusCode": 200
}

Find advisories that intersect the input geometry.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v2/advisory

Scope: advisory:read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry GeoJSON GeoJSON formatted geometry. May be point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 30 nautical miles.
category string See rule category. This is the specified rule category under which you'll be flying.
source string See advisory source. This is the advisory source you wish to return.
startTime string Filters advisories that are active at the same time as, or after startTime. Send as YYYY-MM-DDThh:mmZ.
endTime string Filters advisories that are active at the same time as, or before endTime. Send as YYYY-MM-DDThh:mmZ
maxAltitude integer The maximimum altitude anticipated for the operation. This helps to determine FAA restrictions.

Source

Represents the source of the advsiory or the authority that created the advisory. Additional sources will be made available in the future.

Source Description
faa Federal (FAA) advisories
community State & Local community advisories
all All available advisories

Rule Category

FAA rules are categorized into the following:

Category Description
faa_107 FAA Commercial UAS Flight.
faa_44809 FAA Recreational UAS Flight.

FAA Types

FAA advisories can have the following types as detailed below:

Type Description
controlled_airspace Controlled Airspace Classification.
uasfm_ceiling UAS Facility Management Flight Ceiling.
sua_prohibited Prohibited Special Use Airspace.
sua_restricted Restricted Special Use Airspace.
washington_frz Washington DC Flight Restricted Zone.
nsufr_pt Part Time National Security UAS Flight Restriction.
nsufr_ft Full Time National Security UAS Flight Restriction.
stadium Select stadiums containing temporary flight restriction. The stadium points are buffered by 3 nautical miles.
class_e_weather Weather ceiling when flying in class E airspace.
tfr Temporary Flight Restrictions imposed by the FAA to restrict aircraft operations within designated areas.

Community Types

Community advisories can have the following types as detailed below:

Type Description
admin Administrative advisory (e.g. city or utility infrastructure)
emergency Emergency response area (e.g. accident cleanup area)
recreation Recreational advisory (e.g. parks, events, public gatherings)

Severity

Each advisory will return a severity property. These severities are described as follows:

Type Description
grounded Flying within the advisory should not be undertaken without an additional FAA flight waiver
warning Flying within the advsiory area is not restricted, but discouraged for safety reasons
information The advisory is informational

Query Advisories v4 (POST)

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v4/advisory/query' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Point",
    "coordinates": [-84.48662507347596, 34.03243481512578]
  },
  "altitudeUpper": 500,
  "altitudeLower": -100,
  "startTime": "2022-06-01T23:39:00Z",
  "endTime": "2022-06-30T23:39:00Z",
  "geoIDs": ["1300021", "13"]
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v4/advisory/query");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    geometry: {
     type: "Point",
     coordinates: [-84.48662507347596, 34.03243481512578]
    },
    altitudeUpper: 500,
    altitudeLower: -100,
    startTime: "2022-06-01T23:39:00Z",
    endTime: "2022-06-30T23:39:00Z",
    geoIDs: ["1300021", "13"]
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this (dates and times are in UTC, and can be null):

{
    "statusCode": 200,
    "message": "success",
    "data": {
        "features": [
            {
                "type": "Feature",
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [[
                      [-84.48662507347596, 34.03243481512578],
                      [-84.48662507347596, 33.973213117475744],
                      [-84.38990872353155, 33.973213117475744],
                      [-84.38990872353155, 34.03243481512578],
                      [-84.48662507347596, 34.03243481512578]
                    ]]
                },
                "properties": {
                    "advisoryCategory": "emergency",
                    "altitudeLower": 0,
                    "altitudeUpper": 400,
                    "contactEmail": null,
                    "contactPhone": null,
                    "countryGeoID": "1000",
                    "createdBy": "auth0|60147bba7fc91400699b745f",
                    "endTime": "2022-06-30T23:39:00Z",
                    "geoID": "1300021",
                    "id": "79c5620f-81d2-43ad-af38-91bb8deaf7b8",
                    "lastEditedBy": "auth0|61b78959f995f80069dd0d51",
                    "name": "Test MPH",
                    "ovn": null,
                    "published": true,
                    "referenceNumber": null,
                    "startTime": "2022-06-05T23:39:00Z",
                    "tags": [],
                    "timezoneName": "America/New_York",
                    "url": null,
                    "version": 0
                }
            }
        ],
        "type": "FeatureCollection"
    }
}

Find advisories that intersect the input geometry.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v4/advisory/query

Scope: advisory:read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry GeoJSON GeoJSON formatted geometry. Must be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 100 miles.
altitudeUpper number Filter advisories that are flying at or below the specified altitude.
altitudeLower number Filter advisories that are flying at or above the specified altitude.
startTime string Lower bound of the time range filter. Returns advisories that are active at the same time as, or after startTime. Send as YYYY-MM-DDThh:mmZ.
endTime string Upper bound of the time range filter. Returns advisories that are active at the same time as, or before endTime. Send as YYYY-MM-DDThh:mmZ.
geoIDs string[] Filter advisories that are present in the following geo-IDs. Limit of 5 IDs.

Query Advisories v4 (GET)

curl --location -g --request GET 'https://airhub-api-sandbox.airspacelink.com/v4/advisory/query?bbox=[-84.30,33.74,-84.26,33.75]&altitudeUpper=500&altitudeLower=-100&startTime=2022-09-30T12:00:00Z&endTime=2022-09-30T20:00:00Z&geoIDs=[12,13,14,15,16]' --header 'Content-Type: application/json;charset=UTF-8' --header 'Authorization: Bearer <your-access-token>' --header 'x-api-keycurl --location --request GET 'https://airhub-api-sandbox.airspacelink.com/v4/advisory/query?bbox=\[-84.30,33.74,-84.26,33.75\]&altitudeUpper=500&altitudeLower=-100&startTime=2022-09-30T12:00:00Z&endTime=2022-09-30T20:00:00Z&geoIDs=\[12,13,14,15,16\]' --header 'Content-Type: application/json;charset=UTF-8' --header 'Authorization: Bearer <your-access-token>' --header 'x-api-key: <your-api-key>'^C<your-api-key>' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://airhub-api-sandbox.airspacelink.com/v4/advisory/query?bbox=[-84.30,33.74,-84.26,33.75]&altitudeUpper=500&altitudeLower=-100&startTime=2022-09-30T12:00:00Z&endTime=2022-09-30T20:00:00Z&geoIDs=[12,13,14,15,16]");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send();

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this (dates and times are in UTC, and can be null):

{
    "statusCode": 200,
    "message": "success",
    "data": {
        "features": [
            {
                "type": "Feature",
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [[
                      [-84.48662507347596, 34.03243481512578],
                      [-84.48662507347596, 33.973213117475744],
                      [-84.38990872353155, 33.973213117475744],
                      [-84.38990872353155, 34.03243481512578],
                      [-84.48662507347596, 34.03243481512578]
                    ]]
                },
                "properties": {
                    "advisoryCategory": "emergency",
                    "altitudeLower": 0,
                    "altitudeUpper": 400,
                    "contactEmail": null,
                    "contactPhone": null,
                    "countryGeoID": "1000",
                    "createdBy": "auth0|60147bba7fc91400699b745f",
                    "endTime": "2022-06-30T23:39:00Z",
                    "geoID": "1300021",
                    "id": "79c5620f-81d2-43ad-af38-91bb8deaf7b8",
                    "lastEditedBy": "auth0|61b78959f995f80069dd0d51",
                    "name": "Test MPH",
                    "ovn": null,
                    "published": true,
                    "referenceNumber": null,
                    "startTime": "2022-06-05T23:39:00Z",
                    "tags": [],
                    "timezoneName": "America/New_York",
                    "url": null,
                    "version": 0
                }
            }
        ],
        "type": "FeatureCollection"
    }
}

Find advisories that intersect the input bbox.

HTTP Request

GET https://airhub-api-sandbox.airspacelink.com/v4/advisory/query

Scope: advisory:read

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

Query Parameters

Parameter Type Description
bbox BBox Bounding box of area to query advisory. bbox and geoIDs cannot both be omitted.
geoIDs string[] Filter advisories that are present in the following geo-IDs. Limit of 5 IDs.
altitudeUpper number Filter advisories that are flying at or below the specified altitude.
altitudeLower number Filter advisories that are flying at or above the specified altitude.
startTime string Lower bound of the time range filter. Returns advisories that are active at the same time as, or after startTime. Send as YYYY-MM-DDThh:mmZ.
endTime string Upper bound of the time range filter. Returns advisories that are active at the same time as, or before endTime. Send as YYYY-MM-DDThh:mmZ.

Operations

To support LAANC authorizations within 3rd-party applications, the API allows the creation of operations for linking workflows. Each operation includes information such as pilot name and contact information, operation start time and duration, requested altitude, and the operation boundary (shape).

LAANC Linking

Successfully creating an operation will return a URL that may be used to retrieve the operation within the AirHub Portal LAANC application, where they can be submitted for FAA authorization. After submission, authorization status updates will be sent to the URL provided in the callbackUrl parameter. The following is a sample link url (used after the operation has been successfully generated):

https://portal.airspacelink.com/plan/operations/<id>/claim

Operation v2

Callback URL

Airspace Link will not send a unique ID in the payload when making the POST request to the provided callbackUrl. In order to distinguish between different operations, your callbackUrl must include a unique ID which represents your system's internal operation ID. E.g. https://myapp.com/aslCallback/{ID} or https://myapp.com/aslCallback?id={ID}

{
  "authId": "ABCDEF8G2"
  "authStatus": "approved"
  "authStatusDate": "2022-01-28T19:57:57.378Z"
}

Example request payload sent to the URL provided in the callbackUrl parameter.

Example POST tenantless operation with input GeoJSON Polygon

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/operation' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
    "type": "Feature",
    "properties": {"operationName": "test", "category": "faa_107", "startTime": "2023-01-01T12:00:00Z", "timezoneName": "America/New_York", "duration": 55, "maxAltitude": 100},
    "geometry": {"type": "Polygon", "coordinates": [[[-77.83744812011719,40.676211751311484],[-77.82714843749999,40.676211751311484],[-77.82714843749999,40.683241578458706],[-77.83744812011719,40.683241578458706],[-77.83744812011719,40.676211751311484]]]}
  }'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/operation");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    type: "Feature",
    properties: {
      operationName: "Test Operation",
      category: "faa_107",
      startTime: "2023-01-01T12:00:00Z",
      timezoneName: "America/New_York",
      duration: 55,
      maxAltitude: 100,
    },
    geometry: {
      type: "Polygon",
      coordinates: [
        [
          [-77.83744812011719,40.676211751311484],[-77.82714843749999,40.676211751311484],[-77.82714843749999,40.683241578458706],[-77.83744812011719,40.683241578458706],[-77.83744812011719,40.676211751311484],
        ],
      ],
    }
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "statusCode": 200,
  "message": "success",
  "data": {
    "url": "https://portal-sandbox.airspacelink.com/plan/operations/<id>/claim"
  }
}

Example POST tenantless operation with input GeoJSON LineString

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/operation' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
    "type": "Feature",
    "properties": {"operationName": "test", "category": "faa_107", "startTime": "2023-01-01T12:00:00Z", "timezoneName": "America/New_York", "duration": 55, "maxAltitude": 100},
    "geometry": {"type": "LineString", "coordinates": [[-78.37646484375,40.95708558389897],[-78.343505859375,40.95708558389897]]}
  }'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/operation");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    type: "Feature",
    properties: {
      operationName: "Test Operation",
      category: "faa_107",
      startTime: "2023-01-01T12:00:00Z",
      timezoneName: "America/New_York",
      duration: 55,
      maxAltitude: 100,
    },
    geometry: {
      type: "LineString",
      coordinates: [
        [-78.37646484375,40.95708558389897],[-78.343505859375,40.95708558389897],
      ],
    }
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "statusCode": 200,
  "message": "success",
  "data": {
    "url": "https://portal-sandbox.airspacelink.com/plan/operations/<id>/claim"
  }
}

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v2/operation

Scope: operation:create

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

The POST body is expected to be a GeoJSON Feature. The feature's geometry must be a GeoJSON Polygon or LineString.

A request where geometry is a valid GeoJSON LineString will result in a buffered Polygon. FAA requires input geometries for an operation be a valid GeoJSON Polygon. Validation checks are applied to the input LineString/resulting Polygon/or input Polygon:

Parameter Type Description
type static string Feature
geometry object GeoJSON Polygon or GeoJSON LineString
properties object See operation properties

Operation Properties


Parameter Type Description
operationName string Name of the operation.
category string Rule category.
startTime string ISO 8601 compliant start timestamp of the operation.
timezoneName string Operation timezone
duration integer Duration of the operation from 1 - 720 minutes.
maxAltitude integer Maximum requested altitude of the operation from 5 - 400' Above Ground Level.
fixedAltitude boolean If false, the platform will adjust the altitude to remain below any applicable ceiling limits. This makes for easier FAA approvals, but may not meet the parameters of your operation.
callbackUrl string A POST request will be made to this URL when authorization status updates occur. See Callback URL section above for more details.

Rule Category

FAA rules are categorized into the following:

Category Description
faa_107 FAA Commercial UAS Flight.
faa_44809 FAA Recreational UAS Flight.

Risk

Hazard and risk is an important part of the UAS ecosystem. The FAA publishes well established guidelines on how operations should behave with respect to population and other ground-based risk. This set of API resources will help developers quantify these hazards and their associated risk with a geographic boundary.

Hazard

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/hazard' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [-83.33816528320312, 42.20156425714052],
        [-83.2059860229492, 42.20156425714052],
        [-83.2059860229492, 42.274514451885],
        [-83.33816528320312, 42.274514451885],
        [-83.33816528320312, 42.20156425714052]
      ]
    ]
  }
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/hazard");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    geometry: {
      type: "Polygon",
      coordinates: [
        [
          [-83.33816528320312, 42.20156425714052],
          [-83.2059860229492, 42.20156425714052],
          [-83.2059860229492, 42.274514451885],
          [-83.33816528320312, 42.274514451885],
          [-83.33816528320312, 42.20156425714052],
        ],
      ],
    },
  })
);

The above command returns JSON like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "type": "Feature",
      "properties": {
        "Category": "Critical Infrastructure",
        "CategoryType": "Child Care Center",
        "Name": "RIVERSIDE ACADEMY EARLY CHILDHOOD CENTER",
        "Risk": 1,
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [-83.2320785522461, 42.33418438593939],
            [-83.22624206542969, 42.33418438593939],
            [-83.22624206542969, 42.33646849299472],
            [-83.2320785522461, 42.33646849299472],
            [-83.2320785522461, 42.33418438593939]
          ]
        ]
      }
    }
  ]
}

Find hazards that intersect the input geometry.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/hazard

Scope: hazar.read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry object GeoJSON formatted geometry. Available geometries may be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 10 nautical miles.

Ground Type

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/groundType' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Point",
    "coordinates": [
      [-85.52521705627441, 41.7848170756551]
    ]
  },
  "resolution": 10
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/groundType");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    geometry: {
      type: "Point",
      coordinates: [[-85.52521705627441, 41.7848170756551]],
    },
    resolution: 10,
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "data": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-83.108219359342,42.385396234885185],
          [-83.1091231948962,42.38517018839536],
          [-83.10928346569173,42.38450374309799],
          [-83.10853992433273,42.38406334748932],
          [-83.10763610686435,42.38428938593143],
          [-83.10747581266932,42.38495582802976],
          [-83.108219359342,42.385396234885185]
        ]]
      },
      "properties": {
        "density": "Urban",
        "popPerSqMi": 3270.2970129961664,
      }
    },
    ...
  ],
  "message": "success",
  "statusCode": 200
}

Represents the population classification(s) for the input geometry. Returns an array of the population densities and their respective geometries over the input geometry.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/groundType

Scope: hazar:read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry object GeoJSON formatted geometry. Available geometries may be a point, line, or polygon
resolution number The resolution of the output surface. A larger number means finer granularity.

Ground Risk

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/groundRisk' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [-83.33816528320312, 42.20156425714052],
      [-83.2059860229492, 42.20156425714052],
      [-83.2059860229492, 42.274514451885],
      [-83.33816528320312, 42.274514451885],
      [-83.33816528320312, 42.20156425714052]
    ]]
  },
  "maxAltitude": 100,
  "uavWeight": "MICRO",
  "uavType": "HELICOPTER",
  "pilotControl": "SINGLE_PILOT",
  "losType": "VLOS",
  "resolution": 10
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/groundRisk");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    geometry: {
      type: "Polygon",
      coordinates: [[
        [-83.12633514404297,42.36539333502107],
        [-83.06419372558594,42.36539333502107],
        [-83.06419372558594,42.38619069220356],
        [-83.12633514404297,42.38619069220356],
        [-83.12633514404297,42.36539333502107]
      ]]
    },
    maxAltitude: 100,
    uavWeight: "MICRO",
    uavType: "HELICOPTER",
    pilotControl: "SINGLE_PILOT",
    losType: "VLOS",
    resolution: 10
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "status": 200,
  "message": "success",
  "data": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-83.108219359342,42.385396234885185],
          [-83.1091231948962,42.38517018839536],
          [-83.10928346569173,42.38450374309799],
          [-83.10853992433273,42.38406334748932],
          [-83.10763610686435,42.38428938593143],
          [-83.10747581266932,42.38495582802976],
          [-83.108219359342,42.385396234885185]
        ]]
      },
      "properties": {
        "density": "Urban",
        "infrastructureTypes": ["Right of Way"],
        "popPerSqMi": 3270.2970129961664,
        "score": 2.4
      }
    },
    ...
  ]
}

Ground Risk is modeled from a combination of ground-based hazards, altitude, and drone characteristics (e.g. weight, speed, etc).

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/groundRisk

Scope: hazar:read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry object GeoJSON formatted geometry. Available geometries may be a point, line, or polygon.
uavWeight string Describes the weight of the drone.
uavType string Describes the wing type of the drone.
pilotControl string Describes how the drone will be piloted for the operation.
losType string Describes how the pilot will be observing the drone fly during the operation (if at all).
maxAltitude number An integer representing the altitude of the flight in feet. Must be at least 100 feet.
resolution number The resolution of the output surface. Must be an integer 8-10. A larger number means finer granularity.

UAV Weight

Different classifications of drone weights, in pounds

Type Description
micro A drone that weighs ≤ 0.55 pounds
mini A drone that weighs more than micro and ≤ 4.4 pounds
limited A drone that weighs more than mini and ≤ 20.9 pounds
bantam A drone that weighs more than limited

UAV Type

The type of UAV used in the operation

Type Description
fixed_wing A drone using wings for flight
helicopter A drone using a single rotor for flight
multirotor A drone using more than one rotor for flight
hybrid A combination of the other 3 categories listed

Pilot Control

How the drone is to be flown during the operation

Type Description
single_pilot One pilot will fly the drone for the duration of the operation
multiple_pilot Multiple pilots will fly the drone for the duration of the operation
automated_control The drone will be controlled without a pilot

Drone Line of Sight

How the pilot(s) (if any) will observe the drone for the duration of the operation

Type Description
vlos Visual line of sight: the pilot can see the drone throughout the entire operation
evlos Extended visual line of sight: the drone has spotters relaying information to the pilot
bvlos Beyond visual line of sight: the pilot may not see the drone at some point throughout the operation

Meta routes

Metadata

The metadata route shows all the data sources available for usage.

tier refers to the level of permission required to access the given data source.

curl --location --request GET 'https://airhub-api-sandbox.airspacelink.com/v1/metadata' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--header 'referer: <your-application-referer>'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("GET",  "https://airhub-api-sandbox.airspacelink.com/v1/metadata");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.setRequestHeader("referer", "<your-application-referer>");
xhr.send();

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "name": "Airports",
      "code": "airports",
      "description": "Points designated for landing or takeoff",
      "tier": 0
    }
  ]
}

HTTP Request

GET https://airhub-api-sandbox.airspacelink.com/v1/metadata

Required Headers

Parameter Description
Authorization Authorization bearer access_token generated in Authentication step
x-api-key API key supplied to you by Airspace Link
referer The base URL of the client application that will consume the token. For example, https://yourdomain.com.

Aviation

Aviation

Returns intersecting aviation data from the FAA.

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/aviation?buffer=4' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "type": ["sua", "stadium", "airports"],
  "geometry": {
    "type": "Point",
    "coordinates": [-85.52521705627441, 41.7848170756551]
  }
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/aviation?buffer=4");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    type: ["sua", "stadium", "airports"],
    geometry: {
      type: "Point",
      coordinates: [-85.52521705627441, 41.7848170756551],
    },
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "type": "Feature",
      "properties": {
        // ...metadata
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [-83.2320785522461, 42.33418438593939],
            [-83.22624206542969, 42.33418438593939],
            [-83.22624206542969, 42.33646849299472],
            [-83.2320785522461, 42.33646849299472],
            [-83.2320785522461, 42.33418438593939]
          ]
        ]
      }
    }
  ]
}

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/aviation

Scope: aviation:read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

URL Parameters

Parameter Type Description
buffer number Note: only used when type includes airports. buffer specifies the buffer around the airport in nautical miles. If not specified, the default is 3.

JSON POST Body

Parameter Type Description
geometry object GeoJSON formatted geometry. Available geometries may be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 30 nautical miles.
type string An array of zero or more types from FAA types below. Specifying type will limit the results to only include the types that you specify. If you specify no type then all types will be returned.

FAA Types

Below are various FAA data types. Types will be represented by a constant string as detailed below.

Type Description
controlled_airspace Controlled Airspace Classification.
uasfm_ceiling UAS Facility Management Flight Ceiling.
sua Both sua_prohibited and sua_restricted.
washington_frz Washington DC Flight Restricted Zone.
nsufr_pt Part Time National Security UAS Flight Restriction.
nsufr_ft Full Time National Security UAS Flight Restriction.
stadium Select stadiums containing temporary flight restriction. The stadium points are buffered by 3 nautical miles.
airports Points designated for landing or takeoff. Returns all airports within 3 nautical miles of input geometry by default.
airspace_schedule Controlled airspace schedule for select airports across the country (geometry has no bearing on the result).
tfr Temporary Flight Restrictions imposed by the FAA to restrict aircraft operations within designated areas.

Surface

Surface routes provide hexagonal surfaces that describe the terrain, and can be used to quantify risk via suitability surfaces.

Surface v1

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/surface' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "resolution": 9,
  "noFill": true,
  "index": false,
  "features": {
    "schools": {
      "where": "CITY = '\''BATTLE CREEK'\''",
      "fields": ["*"]
    }
  },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [-85.20858764648438, 42.37579287453795],
      [-85.10009765625, 42.37579287453795],
      [-85.10009765625, 42.45436780800864],
      [-85.20858764648438, 42.45436780800864],
      [-85.20858764648438, 42.37579287453795]
    ]]
  }
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/surface");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    "resolution": 9,
    "noFill": true,
    "index": false,
    "features": {
      "schools": {
        "where": "CITY = 'BATTLE CREEK'",
        "fields": ["ADDRESS", "CITY"]
      }
    },
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [-85.20858764648438, 42.37579287453795],
        [-85.10009765625, 42.37579287453795],
        [-85.10009765625, 42.45436780800864],
        [-85.20858764648438, 42.45436780800864],
        [-85.20858764648438, 42.37579287453795]
      ]]
    }
  })
);

The above command returns JSON like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-85.15551950378466, 42.40390655703839],
          [-85.15743139843995, 42.40275510469299],
          [-85.15693125519239, 42.40099262351432],
          [-85.1545193727733, 42.40038155809197],
          [-85.1526074934986, 42.401532929461865],
          [-85.15310748125742, 42.403295447227336],
          [-85.15551950378466, 42.40390655703839]
        ]]
      },
      "properties": {
        "index": "89274822373ffff",
        "schools": {
          "ADDRESS": ["7422 POORMAN RD"],
          "CITY": ["BATTLE CREEK"]
        }
      }
    },
    ...
  ]
}

Generate a surface with any data sources you request.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/surface

Scope: surface:create

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry geojson GeoJSON formatted geometry. Available geometries may be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 10 nautical miles.
features object Key-value pairs with the key being a metadata source and the value being an object of parameters to the source.
resolution number The resolution of the output surface. A larger number means finer granularity.
noFill bool If there are no features in a particular hex, don't return it to reduce network latency.
index bool Instead of returning GeoJSON, return the indices of the hexagons.
raw bool This will return data as GeoJSON without spatially indexing it. Overrides index, resolution, and noFill.

Parameters object

Parameter Type Description
fields string[] The fields of the metadata source you'd like to return.
where string The where clause to apply to the metadata source.
weight float When computing risk, multiply the final risk score by this number if the feature is present.

Suitability Surface

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/suitability' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "resolution": 9,
  "noFill": true,
  "index": false,
  "maxAltitude": 150,
  "uavWeight": "MICRO",
  "uavType": "FIXED_WING",
  "pilotControl": "SINGLE_PILOT",
  "losType": "VLOS",
  "features": {
    "streams": {
      "where": "FTYPE = 'Artificial Path'",
      "fields": ["*"]
    }
  },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [-85.20858764648438, 42.37579287453795],
      [-85.10009765625, 42.37579287453795],
      [-85.10009765625, 42.45436780800864],
      [-85.20858764648438, 42.45436780800864],
      [-85.20858764648438, 42.37579287453795]
    ]]
  }
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/suitability");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    "resolution": 9,
    "noFill": true,
    "index": false,
    "maxAltitude": 150,
    "uavWeight": "MICRO",
    "uavType": "FIXED_WING",
    "pilotControl": "SINGLE_PILOT",
    "losType": "VLOS",
    "features": {
      "streams": {
        "where": "FTYPE = 'Artificial Path'",
        "fields": ["*"]
      }
    },
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [-85.20858764648438, 42.37579287453795],
        [-85.10009765625, 42.37579287453795],
        [-85.10009765625, 42.45436780800864],
        [-85.20858764648438, 42.45436780800864],
        [-85.20858764648438, 42.37579287453795]
      ]]
    }
  })
);

The above command returns JSON like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-85.18484270344246, 42.444050316443914],
          [-85.18675542682136, 42.4428978045579  ],
          [-85.18625375256725, 42.44113470334944 ],
          [-85.18383951060697, 42.44052407732911 ],
          [-85.18192680245832, 42.44167650818921 ],
          [-85.18242832103469, 42.44343964609331 ],
          [-85.18484270344246, 42.444050316443914]
        ]]
      },
      "properties": {
        "density": "Rural",
        "infrastructureTypes": [],
        "popPerSqMi": 49.17739869167168,
        "score": 1.7,
        "suitableFeatures": ["streams"]
      }
    },
    ...
  ]
}

Generate a suitability surface with any data sources you request. Suitability surfaces are similar to computing risk, but allow you to inject features into the risk computation that are consistent with your concept of operations.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/suitability

Scope: surface:create

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry geojson GeoJSON formatted geometry. Available geometries may be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 10 nautical miles.
uavWeight string Describes the weight of the drone.
uavType string Describes the wing type of the drone.
pilotControl string Describes how the drone will be piloted for the operation.
losType string Describes how the pilot will be observing the drone fly during the operation (if at all).
maxAltitude number An integer representing the altitude of the flight in feet. Must be at least 100 feet.
features object Key-value pairs with the key being a metadata source and the value being an object of parameters to the source.
resolution number The resolution of the output surface. A larger number means finer granularity.
index bool Instead of returning GeoJSON, return the indices of the hexagons.

Surface v2 GeoJSON

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/surface/geojson' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [-83.2437515258789, 42.26714700815231],
        [-83.05904388427734, 42.26714700815231],
        [-83.05904388427734, 42.347126562355115],
        [-83.2437515258789, 42.347126562355115],
        [-83.2437515258789, 42.26714700815231]
      ]
    ]
  },
  "layers": [
    {
      "code": "roads",
      "fields": [ "*" ]
    },
    {
      "code": "railroad_overpass",
      "fields": [ "*" ]
    }
  ],
  "resolution": 9
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/surface/geojson");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-83.2437515258789, 42.26714700815231],
          [-83.05904388427734, 42.26714700815231],
          [-83.05904388427734, 42.347126562355115],
          [-83.2437515258789, 42.347126562355115],
          [-83.2437515258789, 42.26714700815231]
        ]
      ]
    },
    "layers": [
      {
        "code": "roads",
        "fields": [ "*" ]
      },
      {
        "code": "railroad_overpass",
        "fields": [ "*" ]
      }
    ],
    "resolution": 9,
  })
);

The above command returns JSON like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [
            -83.114913,
            42.342732
          ],
          [
            -83.1149241,
            42.3427475
          ],
          [
            -83.1149816,
            42.342827799999995
          ]
        ]
      },
      "properties": {
        "highway": "residential",
        "lane": "2",
        "last_editor": null,
        "last_update": null,
        "name": "30th Street",
        "osm_id": "8728918",
        "surface": null,
        "type": "roads",
        "width": null
      }
    },
    ...
  ]
}

Returns the same format of response data as the base endpoint, but instead of hexes it contains GeoJSON. Additionally, this endpoint returns the entire GeoJSON feature of anything that intersects with the area you specify in the geometry parameter.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v2/surface/geojson

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Request body

Parameter Type Description
geometry geojson GeoJSON formatted geometry. Available geometries may be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 10 nautical miles.
layers object[] Array of layer objects. Valid length of 1-5.
resolution number The resolution of the output surface. A larger number means finer granularity.

Surface v2 Hexbin

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/surface' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [-83.2437515258789, 42.26714700815231],
        [-83.05904388427734, 42.26714700815231],
        [-83.05904388427734, 42.347126562355115],
        [-83.2437515258789, 42.347126562355115],
        [-83.2437515258789, 42.26714700815231]
      ]
    ]
  },
  "layers": [
    {
      "code": "roads",
      "fields": [ "*" ],
      "where": ["=", "highway", "residential"]
    },
    {
      "code": "railroad_overpass",
      "fields": [ "*" ]
    }
  ],
  "resolution": 9,
  "noFill": true,
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/surface");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-83.2437515258789, 42.26714700815231],
          [-83.05904388427734, 42.26714700815231],
          [-83.05904388427734, 42.347126562355115],
          [-83.2437515258789, 42.347126562355115],
          [-83.2437515258789, 42.26714700815231]
        ]
      ]
    },
    "layers": [
      {
        "code": "roads",
        "fields": [ "*" ]
      },
      {
        "code": "railroad_overpass",
        "fields": [ "*" ]
      }
    ],
    "resolution": 9,
    "noFill": true,
  })
);

The above command returns JSON like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "hexes": [
        "892ab2cec2fffff"
      ],
      "props": {
        "highway": "residential",
        "lane": "2",
        "last_editor": null,
        "last_update": null,
        "name": "30th Street",
        "osm_id": "8728918",
        "surface": null,
        "type": "roads",
        "width": null
      }
    },
    ...
  ]
}

Generate a surface with any data sources you request. Returns a hexbin payload that includes hexes contained within the area you specify in the geometry parameter. For a GeoJSON response, use the Surface GeoJSON endpoint.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v2/surface

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry geojson GeoJSON formatted geometry. Available geometries may be a point, line, or polygon. The resulting bounding box of the geometry can't have a side length greater than 10 nautical miles.
layers object[] Array of layer objects. Valid length of 1-5.
resolution number The resolution of the output surface. A larger number means finer granularity.

Types

Surface generation is the foundation of all the advanced features of the Airspace Link API. It has its own set of types and lexicon that assist in making the queries intuitive and powerful.

Layer Object

The layer object represents the building block for requesting surface information. At a minimum, provide a code and that data source will be fetched. You can access attributes using the JSON key fields, and you can provide a filter using the JSON key where.

Parameter Type Description
code string A metadata source.
fields string[] The fields of the metadata source you'd like to return. Setting "fields": ["*"] will return all valid fields for supported data types.
where <where> A pseudo-SQL expression tree. Click here for information on how to generate one.
risk float64 An optional risk value to assign to the layer. Only relevant when requesting risk surfaces.

SQL Expression Tree

Backus-Naur Form

// Whitespace between expressions is allowed in your queries, but is omitted
// from the grammar for clarity's sake

<where> ::= <logical_expression> | <comparison_expression>

<logical_expression> ::= "[" <logical_lexeme> "," (<logical_expression> | <comparison_expression>) "," (<logical_expression> | <comparison_expression>) ("," (<logical_expression> | <comparison_expression>))* "]"

<comparison_expression> ::= "[" <comparison_lexeme> "," <alphanumeric_string> "," <valid_json_value> "]"

<comparison_lexeme> ::= "\"" ("=" | "<=" | ">=" | "<" | ">" | "!=") "\""

<logical_lexeme> ::= "\"" ("AND" | "OR") "\""

<valid_json_value> ::= "true" | "false" | "null" | <string> | <number>

Simple comparisons

# Altitude less than 300ft:
["<", "altitude_ft", 300]

# Anything that's not a highway:
["!=", "street_type", "highway"]

# Anything that's a highway:
["=", "street_type", "highway"]

Logical operators

# UASFM grids between 200 and 300ft:
["AND", [">=", "CEILING", 200], ["<=", "CEILING", 300]]

# UASFM grids at a specific airport between 200-300ft
["AND", ["=", "APT1_ICAO", "KDET"], [">=", "CEILING", 200], ["<=", "CEILING", 300]]

# UASFM grids at a variety of potential airports that satisfy 200-300ft:
["AND", ["OR", ["=", "APT1_ICAO", "KDET"], ["=", "APT1_ICAO", "KDTW"]],
        [">=", "CEILING", 200],
        ["<=", "CEILING", 300]]

Several API endpoints require generating surfaces, and all surface generation supports advanced querying. You can provide a filter via a tree data structure for each resource you request that will be parsed out and produce a filter that suits your use case.

Logical operators

Operator Arity Description
AND Binary or greater A standard logical AND. All the arguments provided to the AND will be nested.
OR Binary or greater A standard logical OR. All the arguments provided to the OR will be nested.

Comparison operators

Operator Arity Description
= Binary = does an equality check on the field and the passed value. Type coercion may be performed if the types are different.
> Binary > checks the field is greater than the passed value. Type coercion may be performed if the types are different.
< Binary < checks the field is less than the passed value. Type coercion may be performed if the types are different.
<= Binary <= checks the field is less than or equal to the passed value. Type coercion may be performed if the types are different.
>= Binary >= checks the field is greater than or equal to the passed value. Type coercion may be performed if the types are different.
!= Binary != checks the field is not equal to the passed value. Type coercion may be performed if the types are different.

Risk surface V2

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/classify' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '    {
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-83.273277,42.333423],
          [-83.273277,42.376047],
          [-83.241692,42.376047],
          [-83.241692,42.333423],
          [-83.273277,42.333423]
        ]]
      },
      "layers": [
        {
          "code": "streams",
          "risk": 1,
          "where": ["<=", "meters", 400] // only return streams that have a length <= 400 meters
        },
        {
          "code": "airports",
          "risk": 4
        }
      ],
      "resolution": 9
    }
'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/classify");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify(    {
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-83.273277,42.333423],
          [-83.273277,42.376047],
          [-83.241692,42.376047],
          [-83.241692,42.333423],
          [-83.273277,42.333423]
        ]]
      },
      "layers": [
        {
          "code": "streams",
          "risk": 1,
          "where": ["<=", "meters", 400] // only return streams that have a length <= 400 meters
        },
        {
          "code": "airports",
          "risk": 4
        }
      ],
      "resolution": 9
    }
)
);

The above command returns JSON like this:

{
    "statusCode": 200,
    "message": "success",
    "data": {
        "bitmaskMap": {
            "streams": {
                "bitmask": 1,
                "risk": 1
            },
            "airports": {
                "bitmask": 2,
                "risk": 4
            }
        },
        "hexes": [
            {
                "bitmask": 1, // only a stream: 0x0001
                "index": "892ab2cd1bbffff",
                "risk": 1 // streams were marked with a risk of 1
            },
            {
                "bitmask": 2, // only an airport: 0x0010
                "index": "892ab2cd1bbfff1",
                "risk": 4 // airports were marked with a risk of 4
            },
            {
                "bitmask": 3, // both a stream and an airport: 0x0011
                "index": "892ab2cd1bbfff2",
                "risk": 4 // the larger of the risks is 4
            }
      // ...
        ]
    }
}

Generate a risk surface with any data sources you request. Data are returned back as h3 indices with a bitmask denoting which data sources are present in that index, and optionally a risk score. The risk score is the highest risk feature present in the hex index. If you leave out risk scores for every entry in your layers array, the server will not return a risk score. If nothing's present in the requested geometry, the server will not send back an index.

Using the bitmaskMap

The returned data key will have a bitmaskMap member you can use to efficiently determine the presence or absence of any of the requested data sources. Given the example with streams and airports, we can determine if an index contains none, one of, or both streams/airports by doing a logical &:

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v2/classify

Scope: surface:create

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry geojson GeoJSON formatted geometry. Available geometries may be a point or polygon. The resulting bounding box of the geometry can't have a side length greater than 10 nautical miles.
layers object[] An array of layers objects
resolution number The resolution of the output surface. A larger number means finer granularity.

Route

Route V1

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/route' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
    "losType": "BVLOS",
    "maxAltitude": 100,
    "pilotControl": "SINGLE_PILOT",
    "resolution": 9,
    "returnCorridor": true,
    "returnNetwork": true,
    "returnSurface": true,
    "uavType": "HYBRID",
    "uavWeight": "LIMITED",
    "geometry": {
        "coordinates": [
            [
                -83.237915,
                42.316416
            ],
            [
                -83.205643,
                42.304991
            ]
        ],
        "type": "MultiPoint"
    },
    "features": {
        "streams": {
            "weight": 0.5
        }
    }
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/route");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    "losType": "BVLOS",
    "maxAltitude": 100,
    "pilotControl": "SINGLE_PILOT",
    "resolution": 9,
    "returnCorridor": true,
    "returnNetwork": true,
    "returnSurface": true,
    "uavType": "HYBRID",
    "uavWeight": "LIMITED",
    "geometry": {
        "coordinates": [
            [
                -83.237915,
                42.316416
            ],
            [
                -83.205643,
                42.304991
            ]
        ],
        "type": "MultiPoint"
    },
    "features": {
        "streams": {
            "weight": 0.5
        }
    }
  })
)

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
    "statusCode": 200,
    "message": "success",
    "data": {
        "corridor": [
            "892ab2cdcafffff",
            "892ab2cdddbffff",
            "892ab2cddc3ffff",
            "892ab2cddd7ffff",
            "892ab2cdd9bffff",
            "892ab2cdd83ffff",
            "892ab2cdd87ffff",
            "892ab2cce4bffff",
            "892ab2cce43ffff",
            "892ab2cce47ffff",
            "892ab2cce73ffff"
        ],
        "network": {
            "type": "MultiLineString",
            "coordinates": [
                [
                    [-83.22132621971751,42.306309536604154],
                    [-83.20827680443215,42.30771086507444]
                ],
                ...
            ]
        },
        "route": {
            "type": "LineString",
            "coordinates": [
                [-83.237915,42.316416],
                [-83.23412143346106,42.313110874461174],
                [-83.22695599604445,42.31115564289149],
                [-83.22456763561581,42.31050380530632],
                [-83.21262672407333,42.30724391460332],
                [-83.21023871992755,42.30659179593648],
                [-83.205643,42.304991]
            ]
        },
        "surface": {
            "892ab2cc267ffff": {
                "density": "Suburban",
                "infrastructureTypes": [],
                "popPerSqMi": 418.00788887920925,
                "score": 1,
                "suitableFeatures": [
                    "streams"
                ]
            },
          ...
        }
    }
}

Returns a GeoJSON LineString representing a straight line optimizing risk and distance.

The MultiPoint input object will be used as the origin and destination for the route.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/route

Scope: route:create

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

The POST body's geometry property is expected to be a GeoJSON MultiPoint. If more than 100 points are supplied, the API will reject the request.

Parameter Type Description
geometry GeoJSON MultiPoint An ordered list of points for the route.
uavWeight string Describes the weight of the drone.
uavType string Describes the wing type of the drone.
pilotControl string Describes how the drone will be piloted for the operation.
losType string Describes how the pilot will be observing the drone fly during the operation (if at all).
maxAltitude number An integer representing the altitude of the flight in feet. Must be at least 100 feet.
features object Key-value pairs with the key being a metadata source and the value being an object of parameters representing suitable/unsuitable features.
resolution number The resolution of the output surface. A larger number means finer granularity.
returnCorridor boolean If true, return the hex corridor taken by the algorithm.
returnNetwork boolean If true, return the network considered by the algorithm.
returnSurface boolean If true, return the suitability surface considered by the algorithm.

Route V2

Passing a user-defined surface:

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/route' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
      "resolution": 9,
      "surface": {
        "892ab2cdcafffff": 1.5,
        "892ab2cdddbffff": 1.1,
        "892ab2cddc3ffff": 1.1,
        "892ab2cddd7ffff": 1.0,
        "892ab2cdd9bffff": 1.3,
        "892ab2cdd83ffff": 2.1,
        "892ab2cdd87ffff": 0.1,
        "892ab2cce4bffff": 8.0
      },
      "waypoints": {
        "type": "MultiPoint",
        "coordinates": [
            [-83.237915,42.316416],
            [-83.205643,42.304991]
        ]
      }
}
'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/route");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
      "resolution": 9,
      "surface": {
        "892ab2cdcafffff": 1.5,
        "892ab2cdddbffff": 1.1,
        "892ab2cddc3ffff": 1.1,
        "892ab2cddd7ffff": 1.0,
        "892ab2cdd9bffff": 1.3,
        "892ab2cdd83ffff": 2.1,
        "892ab2cdd87ffff": 0.1,
        "892ab2cce4bffff": 8.0
      },
      "waypoints": {
        "type": "MultiPoint",
        "coordinates": [
            [-83.237915,42.316416],
            [-83.205643,42.304991]
        ]
      }
}
)
);

Passing a geometry and layers to generate a risk surface

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/route' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '    {
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-83.273277,42.333423],
          [-83.273277,42.376047],
          [-83.241692,42.376047],
          [-83.241692,42.333423],
          [-83.273277,42.333423]
        ]]
      },
      "layers": [
        {
          "code": "streams",
          "risk": 1
        },
        {
          "code": "airports",
          "risk": 4
        }
      ],
      "resolution": 9,
      "waypoints": {
        "type": "MultiPoint",
        "coordinates": [
            [-83.237915,42.316416],
            [-83.205643,42.304991]
        ]
    }
'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/route");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify(    {
      "geometry": {
        "type": "Polygon",
        "coordinates": [[
          [-83.273277,42.333423],
          [-83.273277,42.376047],
          [-83.241692,42.376047],
          [-83.241692,42.333423],
          [-83.273277,42.333423]
        ]]
      },
      "layers": [
        {
          "code": "streams",
          "risk": 1
        },
        {
          "code": "airports",
          "risk": 4
        }
      ],
      "resolution": 9,
      "waypoints": {
        "type": "MultiPoint",
        "coordinates": [
            [-83.237915,42.316416],
            [-83.205643,42.304991]
        ]
    }
)
);

Passing only a risk model:

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v2/route' \
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '    {
      "layers": [
        {
          "code": "streams",
          "risk": 1
        },
        {
          "code": "airports",
          "risk": 4
        }
      ],
      "resolution": 9,
      "waypoints": {
        "type": "MultiPoint",
        "coordinates": [
            [-83.237915,42.316416],
            [-83.205643,42.304991]
        ]
    }
'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v2/route");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify(    {
      "layers": [
        {
          "code": "streams",
          "risk": 1
        },
        {
          "code": "airports",
          "risk": 4
        }
      ],
      "resolution": 9,
      "waypoints": {
        "type": "MultiPoint",
        "coordinates": [
            [-83.237915,42.316416],
            [-83.205643,42.304991]
        ]
    }
)
);

Any of the above return JSON like this:

{
    "statusCode": 200,
    "message": "success",
    "data": {
        "bitmaskMap": {
            "streams": {
                "bitmask": 1,
                "risk": 1
            },
            "airports": {
                "bitmask": 2,
                "risk": 4
            }
        },
        "hexes": [
            {
                "bitmask": 1, // only a stream: 0x0001
                "index": "892ab2cd1bbffff",
                "risk": 1
            },
            {
                "bitmask": 2, // only an airport: 0x0010
                "index": "892ab2cd1bbfff1",
                "risk": 4 // airports were marked with a risk of 4
            },
            {
                "bitmask": 3, // both a stream and an airport: 0x0011
                "index": "892ab2cd1bbfff2",
                "risk": 4 // 
            }
            // ...
        ]
    }
}

Returns a GeoJSON LineString representing a straight line optimizing risk and distance. There are 3 ways to generate a route:

  1. Send a full risk surface. Pass in a full risk surface to route against to skip generating one. The surface must connect all the waypoints or the route will be unsolvable.
  2. Send a risk model and a geometry. Pass in a risk model and a geometry to generate a risk surface that will be used to route against. The geometry passed must connect all waypoints or the route will be unsolvable.
  3. Send only a risk model. We will generate a geometry for you by buffering out a corridor containing all your waypoints.

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v2/route

Scope: surface:create

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
waypoints GeoJSON MultiPoint A multipoint identifying origin and destination(s) to route sequentially.
resolution number The resolution you'd like the server to use for your risk surface. This number should match the resolution of all indices populating surface if you choose to pass it.
layers object[] An array of layers objects. If you pass in a surface, this will be ignored.
geometry GeoJSON Polygon An polygon to pass that connects all the waypoints passed to use for creating a risk surface. If you passed in a surface, this will be ignored. If you don't pass a surface or geometry, the server will pick the geometry to generate the surface for you.

Check

Check Airspace

Returns a payload containing properties that inform whether Airspace Authorization is required.

curl --location --request POST 'https://airhub-api-sandbox.airspacelink.com/v1/check/airspace' 
--header 'Content-Type: application/json;charset=UTF-8' \
--header 'Authorization: Bearer <your-access-token>' \
--header 'x-api-key: <your-api-key>' \
--data-raw '{
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [-83.21096420288086, 42.35829022102702],
        [-83.19843292236327, 42.35829022102702],
        [-83.19843292236327, 42.36552016904453],
        [-83.21096420288086, 42.36552016904453],
        [-83.21096420288086, 42.35829022102702]
      ]
    ]
  },
  "startTime": "2022-09-22T14:00:00.00Z",
  "endTime": "2022-09-22T15:00:00.00Z"
}'
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE && this.status === 200) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://airhub-api-sandbox.airspacelink.com/v1/check/airspace");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.setRequestHeader("Authorization", "Bearer <your-access-token>");
xhr.setRequestHeader("x-api-key", "<your-api-key>");
xhr.send(
  JSON.stringify({
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-83.21096420288086, 42.35829022102702],
          [-83.19843292236327, 42.35829022102702],
          [-83.19843292236327, 42.36552016904453],
          [-83.21096420288086, 42.36552016904453],
          [-83.21096420288086, 42.35829022102702]
        ]
      ]
    },
    "startTime": "2022-09-22T14:00:00.000Z",
    "endTime": "2022-09-22T15:00:00.000Z"
  })
);

Make sure to replace <your-xxx> with your applicable values.

The above command returns JSON structured like this:

{
  "statusCode": 200,
  "message": "success",
  "data": [
    {
      "controlled": false,
      "enabled": false,
      "restricted": false
    }
  ]
}

Controlled: Represents airspace that is monitored and managed by air traffic control. If true, rules implemented by air traffic apply.

Enabled: Applies to controlled grids/areas with altitude ceilings. At times, these grids may be disabled. If true, the altitude ceilings are in effect and require authorization in accordance with the rules and ceilings. If false, alternative authorization is likely required. For example, the Drone Zone in the US.

Restricted: Denotes airspace that is subject to limitations or may be prohibited entirely. If true, drone flights cannot be authorized during a time window or in some cases into perpetuity.

Examples:

  1. Airspace is uncontrolled and does not require authorization { "controlled": false, "enabled": true | false, "restricted": false }
  2. Airspace is controlled with enabled grids/areas and requires authorization { "controlled": true, "enabled": true, "restricted": false }
  3. Airspace is restricted and drone flights are not allowed { "controlled": false, "enabled": false, "restricted": true }
  4. Airspace is controlled but grids/areas are not enabled and alternative authorization is required { "controlled": true, "enabled": false, "restricted": false }

HTTP Request

POST https://airhub-api-sandbox.airspacelink.com/v1/check/airspace

Scope: aviation:read

Why POST and not GET? GeoJSON strings can often become quite long depending on the complexity of the coordinates. We use a POST to overcome any browser url length limitations when using this API in the browser.

Required Headers

Parameter Description
Content-Type application/json;charset=UTF-8
Authorization Authorization bearer accessToken generated in Authentication step
x-api-key API key supplied to you by Airspace Link

JSON POST Body

Parameter Type Description
geometry object GeoJSON formatted geometry. Available geometries may be a polygon.
startTime string ISO 8601 compliant start timestamp of the operation.
endTime string ISO 8601 compliant start timestamp of the operation.

Errors

The AirHub API uses the following error codes:

Error Code Meaning
400 Bad Request: Your request is invalid.
401 Unauthorized: Your API key is wrong or your accessToken is malformed.
403 Forbidden: The resource requested is not available to your user or your request headers/parameters are malformed.
404 Not Found: The specified resource could not be found.
405 Method Not Allowed: You tried to access a resource with an invalid method.
406 Not Acceptable: You requested a format that isn't json.
410 Gone: The resource has been removed from our servers.
422 Unprocessable: The inputs could not be processed.
500 Internal Server Error: We had a problem with our server. Try again later or adjust your request.
503 Service Unavailable: We're temporarily offline for maintenance. Please try again later.