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
Operations created via the sandbox API link to the sandbox Portal environment.
Operations created via the production API link to the production Portal environment.
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:
- LineString must have an array of positions (float64) in accordance with the RFC7946 spec
- LineString resulting in a buffered Polygon must not have interior rings (doughnut shape)
- LineString resulting a buffered Polygon must not have an area greater than 10 square miles or a side length greater than 10 nautical miles
- Polygon must be closed; the first coordinates match the last in the array
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 type s 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 &
:
hex.bitmask == 0x0011
returnstrue
if the hex has both a stream and airport contained in it.hex.bitmask & 0x0010 > 0
returnstrue
if the hex has at least an airport contained in it.hex.bitmask & 0x0001 > 0
returnstrue
if the hex has at least a stream contained in it.hex.bitmask == 0x0010
returnstrue
if the hex has only an airport contained in it.hex.bitmask == 0x0001
returnstrue
if the hex has only a stream contained in it.hex.bitmask & 0x0000 > 0
will never be true; the server will only return back hexes that have features.
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:
- 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.
- 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.
- 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:
- Airspace is uncontrolled and does not require authorization
{ "controlled": false, "enabled": true | false, "restricted": false }
- Airspace is controlled with enabled grids/areas and requires authorization
{ "controlled": true, "enabled": true, "restricted": false }
- Airspace is restricted and drone flights are not allowed
{ "controlled": false, "enabled": false, "restricted": true }
- 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. |