Strategic Conflict Resolution

Use our platform to help with strategic conflict resolution either against your own submitted flight plans, or against all flight plans others have opted-in to share across our network.

Strategic Flight Deconfliction API

This service provides pre-flight deconfliction of flight plans that have been submitted to Altitude Angel. During implementation, one can choose to have their flight plan evaluated against just their own flight plans, or against all flight plans that have been shared publicly in the Altitude Angel network (see ConflictResolutionScope).

A key tenet of aviation safety is planning to avoid coming into proximity with other air users before one starts a flight. This is often referred to as "plan-to-avoid", and should be among the minimum initial checks conducted prior to taking-off. In traditional aviation, deconfliction is handled differently for different classes of air traffic, but not always uniformly. For example, commercial airlines typically share their flight plans ahead of time with each other, but general aviation may only share flight plans at a local flying-club level.

This API can be used to store your flight plans securely on the Altitude Angel network up to fourteen days in the future, privately (just for your use), or publicly (for deconfliction across public flights shared via the Altitude Angel network). Each subsequent flight plan you submit will be evaluated for conflicts with other flight plans, according to the parameters you set.

🚧

Caution

Before using this service, you should study this documentation carefully and, in particular, familiarise yourself with the limitations and performance characteristics which are explained below.

If you have questions before you use the service, please contact us.

Scenarios

The service has been designed to cater for usage in both single-tenant and multi-tenant scenarios, and is ideally suited to the following specific use cases:

  1. You are building a fleet management solution and wish to ensure that, pre-flight, your flights are guaranteed never to conflict with each other or with other flights published via and available to others on the Altitude Angel network.

  2. You are building a single-tenant or multi-tenant flight-planning or process management system to facilitate best practices for drone flight, and you want to provide your users with the capability to plan flights that are conflict-free.

  3. You are a drone manufacturer and building flight control software which features automated flight, or flight-path based control modes, and you want to ensure that a) none of your other customers' flights will conflict with each other, or b) none of your customer's flights will conflict with each other or any flight published on the Altitude Angel network.

Limitations

❗️

This service does not have knowledge about every flight.

This service does not have knowledge of every manned or unmanned flight. It is opt-in only, and we continue to see more and more flights each month. Depending on the ConflictResolutionScope you have requested, the service does provide guarantees that your flight plan is free from conflicts with any others if the conditions have been met.

The service currently checks against:

  1. Valid flights that you have submitted into the API which are within their validity period and

  2. Valid flights which other users of this API have indicated may be shared publicly, via any of Altitude Angel's first-party flight planning products (such as via www.dronesafetymap.com), or that another developer using this API has agreed to share with others (i.e. the ConflictResolutionScope is set to Global).

👍

What is a 'valid flight'?

A Valid flight is a flight which has been registered and accepted into the Altitude Angel Network, is scheduled to start in the future, or has started but has not yet expired. Developers who submit flights to this service will receive a FlightId and outcomeCode, together with a 200 OK HTTP response once a flight has been accepted as 'valid'.

📘

Use by drones only

This service is intended primarily for use by drone operators. In a future release, we'll add support for flight plans by manned aircraft. This service does not currently receive flight plans for commercial routes operated by airlines, but this is a planned feature.

At this time, we provide de-confliction only for flights which have opted-in to receive this service and as such, is not intended to be used as the sole source of information used in determining whether a flight in any location at any given time shall be free from conflict or not.

Getting started

To access this API, you must first:

  1. Register for a Developer Account
  2. Obtain your API key to authenticate with this service.

📘

If you already have a developer account registered before 23 July 2019

Your existing API key will need manual activation in order to utilise this new service. Please contact us for assistance.

Minimum Requirements and API Characteristics

Minimum TLS Version

This service is accessed via HTTPS using TLS 1.2 or above. Connections from clients running TLS 1.1 or weaker will be rejected.

Base URI

The URIs referenced in this documentation are relative to the base of https://flight.altitudeangel.com.

Always use DNS

Never store the IP address returned through resolution of the DNS Query. We deliver the service via multiple datacentre locations and across a range of IP addresses, and regularly rotate clusters for security and performance reasons. Always resolve the location of the service by making a fresh DNS query (respecting the TTL of the record).

HTTP response codes related only to the status of the HTTP request

A response code of 200 means we have processed your request successfully, not that your flight hasn't conflicted with another. Always inspect the result of the OutcomeCode property in the response.

How this service works

In this section, we explain precisely how the service works by exploring the types of conflict scenarios we can evaluate, how we do this, what responses can be expected and what the limitations of the service are.

❗️

Please carefully understand this section before implementation

It is important that you understand exactly what scenarios this service can, and cannot, evaluate. Management of risk within the airspace is not about the elimination of all risk; it is about the quantification and mitigation of those risks. This service will help to mitigate many associate risks if implemented correctly, but due to its opt-in nature, cannot mitigate all risk associated with a drone operation.

This API receives flight plans and evaluates them against conflicts on a first in wins basis.

Evaluated Conditions - Other Flight Plans

When a flight plan is submitted, it is first checked for conflicts against other flight plans that have been submitted ahead of yours. For a conflict to occur, the submitted flight plan must first intersect with another one temporally; i.e. it is scheduled to take place at the same time as another previously registered flight plan.

Once this condition is met, there are two possible ways the flight plan may conflict with another:

By Proximity

On submission, the entirety of the submitted flight plan (i.e. all of its constituent Parts) are merged, and then have a 'buffer' added to them. If the buffers of any two valid flight plans intersect, or the buffer region of one intersects with the buffer-less region of another, then a conflict of level 2000 (ProximityWarning) will be generated. This means that while the two flight plans come close, according to the data provided to the flight plan service, the operators of the two flights are not planning paths that directly conflict.

The diagram below gives a logical example of how a Proximity Warning is generated:

By Direct Conflict

In this case, if the paths of two flight plans intersect (without a buffer region), then a conflict of level 3000 (DirectConflict) will be returned, and the last-in flight plan will not be stored by Altitude Angel, and no flightPlanId will be issued for the flight.

The diagram below gives a logical example of how a Direct Conflict is generated:

🚧

Altitude is ignored

In the current release version of this service, the conflict resolver does not take into account 'vertical separation'. Instead, all flight plans are treated as if they existed solely on a two-dimensional plane. We will continue to monitor use of this service, international guidance and best practices, and have prepared the service for three-dimensional resolution and plan to release this type of evaluation condition soon.

Creating and submitting your flight plan

This service begins with the submission of a valid Flight Plan, which consists of several key pieces of data.

📘

Not all information is mandatory

Please note that the service has been designed to collect more data than is required for the functionality currently provided, to assist with "future-proofing". We have a roadmap of future development for this service, and developers who are able to provide additional data above the minimum requirements may find it easier to avail of enhancements to this service.

Minimum required fields are indicated in the property description below the sample request.

Below is a conceptual description of the data that we request as part of a flight plan:

  1. Metadata about the flight, primarily used for your own reference, such as a description and summary of the flight.
  2. One (or more) parts, which are effectively 'legs' of a journey that can be detailed routes, or more specific geographies encompassing a general area.
  3. A scheduled start date/time and end date/time, and a maximum altitude (maxAltitude).
  4. Your own token, called externalOperatorId, to enable you to deliver multi-tenant solutions and separate flights belonging from one customer to another.
  5. Any identifiers that might help others in the vicinity identify you, such as an ICAO ADS-B identifier, if your drone or aircraft is equipped with such a piece of equipment.
  6. droneDetails, which describes the phsyical properties of your drone (only required for unmanned aircraft).
  7. The desired conflictResolutionScope, i.e. global or local.
  8. Whether the flight plan is draft or final, which enables you to submit "what-if?" queries against the service without committing to conduct an actual flight.

Refer to the property definition below to determine which parameters are mandatory and which are optional.

🚧

Submit exactly one Flight for each aircraft that will conduct a logical flight.

For example, if you plan to fly a swarm of drones, you could submit one flight for each drone participating in the swarm (if you want this service to provide conflict separation for each individual drone participating in the swarm). Or, you could submit one flight to cover the whole area in which the swarm will fly, but you will then have to provide separation within that area for each individual drone.

In either case, if you choose global scope, others will be informed of your operation so that their flights are not permitted by this service to conflict with yours.

Request

Make an HTTP request to the following URL:

POST https://flight.altitudeangel.com/v1/conflict-resolution/strategic/flight-plans
Authorization: X-AA-ApiKey YOUR_API_KEY_HERE

📘

Don't forget to include the full URL in the POST instruction

... And don't forget to include the prefix "X-AA-ApiKey", plus a space character, before inserting the API key generated via the Developer Portal. If your API key was "123", then the full string value to insert for the "Authorization" header would be "X-AA-ApiKey 123".

Construct the payload of your HTTP request as a JSON document using UTF-8 encoding as follows. The JSON messages below show the minimum and maximum that will be accepted by the API.

{
    "summary": "Flight Title",
    "parts": [
        {
            "id": "1",
            "geography": {
                "type": "LineString",
                "coordinates": [
                    [
                        -1.007995,
                        51.473791
                    ],
                    [
                        -0.982933,
                        51.472722
                    ]
                ]
            },
            "start": "2010-07-31T12:00:00Z",
            "end": "2010-07-31T13:00:00Z",
            "maxAltitude": {
                "datum": "agl",
                "meters": 50
            }
        },
        {
            "id": "2",
            "geography": {
                "type": "LineString",
                "coordinates": [
                    [
                        -0.982933,
                        51.472722
                    ],
                    [
                        -0.987138,
                        51.467897
                    ]
                ]
            },
            "start": "2010-07-31T13:00:00Z",
            "end": "2010-07-31T14:00:00Z",
            "maxAltitude": {
                "datum": "agl",
                "meters": 50
            }
        }
    ],
    "pointOfContact": {
        "firstName": "John",
        "lastName": "Smith",
        "phoneNumber": "+447700900123"
    },
    "conflictResolutionScope": "global"
}
{
    "summary": "Flight Title",
    "description": "Flight Description",
    "parts": [
        {
            "id": "1",
            "geography": {
                "type": "LineString",
                "coordinates": [
                    [
                        -1.007995,
                        51.473791
                    ],
                    [
                        -0.982933,
                        51.472722
                    ]
                ]
            },
            "start": "2010-07-31T12:00:00Z",
            "end": "2010-07-31T13:00:00Z",
            "maxAltitude": {
                "datum": "agl",
                "meters": 50
            }
        },
        {
            "id": "2",
            "geography": {
                "type": "LineString",
                "coordinates": [
                    [
                        -0.982933,
                        51.472722
                    ],
                    [
                        -0.987138,
                        51.467897
                    ]
                ]
            },
            "start": "2010-07-31T13:00:00Z",
            "end": "2010-07-31T14:00:00Z",
            "maxAltitude": {
                "datum": "agl",
                "meters": 50
            }
        }
    ],
    "externalOperatorId": "ABC123",
    "identifiers": {
        "ADSB": "AAA111"
    },
    "pointOfContact": {
        "firstName": "John",
        "lastName": "Smith",
        "phoneNumber": "+447700900123"
    },
    "droneDetails": {
        "color": "Purple",
        "markings": "Go faster stripes",
        "airFrame": "rotary",
        "weight": 150,
        "maxWeight": 250
    },
    "conflictResolutionScope": "global",
    "isDraft": false
}

Anatomy of a Flight Plan

An explanation of the properties in the above JSON document is provided below. Required properties are marked with an asterisk *.

Parameter NameDatatypeDescription
summary*stringSummary of the flight or operation. This may be shared with others if you choose the global scope.
descriptionstringMore details about the flight, such as the nature of the activity being undertaken.
parts*flightPart[]Each constituent segment that makes up the entire flight.
externalOperatorIdstringAn identifier for the user that 'owns' the flight that is specific to your implementation, eg "user-123456". We use these to help you correlate in a multi-tenant scenario.
identifiersDictionary[string, string]Identifiers/signals given off by the craft that can be used to identify it.
pointOfContact*contactDetailsThe details for the point of contact that will be responsible for the drone's flight.
droneDetailsdroneDetailsThe physical and performance characteristics of the drone that will be making the flight.
conflictResolutionScope*stringThe scope under which the flight plan will be tested for conflictions against.
isDraftboolWhether or not the flight plan should be tangibly submitted.

A whole flight plan consists of one or many flight parts, where each is a distinct geographical, spatial, and altitudinal segment.

parts

The parts property is an array of flightPart objects.
A flightPart is logically a specific 'leg' of a journey. It's entirely your choice whether you wish to use multiple parts to break-up a journey and this is largely included for future compatibility. Please note that a flightPart is not a mechanism to specify multiple vehicles.

flightPart

Parameter NameDatatypeDescription
id*stringA unique identifier for this part of the flight.
geography*geoJSONThe spatial area that this part will occupy. It should be formatted as GeoJSON, and can be either a LineString, Polygon, or Point.
start*dateTimeThe ISO8601 date and time, including timezone specifier, at which this flight segment will begin.
end*dateTimeThe ISO8601 date and time, including timezone specifier, at which this flight segment will be completed.
maxAltitude*altitudeThe highest point that will be reached in this part.

Depending on the type of flight and how you want to express it, different GeoJSON objects may be used. Any of:

  • Polygon: The flight will be taking place throughout a given area;
  • LineString/Point: The flight will be travelling through a set of waypoints.

altitude

An altitude is a combination of both height, and the datum against it was measured. It takes the following structure:

Parameter NameDatatypeDescription
datum*datumThe datum that the altitude is measured against.
meters*doubleThe height, in meters.

The following datums are supported:

ValueNameDescription
wgs84WGS-84Altitude expressed in meters above the WGS-84 ellipsoid (most commonly, this is used by GPS chips in a raw NMEA stream).
aglAbove ground levelThe altitude is given as a positive offset 'above ground level' at the specified coordinates.

contactDetails

Contact details give information on the individual responsible for the flight, who should be available to contact for the duration of the it.

Parameter NameDatatypeDescription
firstName*stringFirst name of the contact.
lastName*stringLast name of the contact.
phoneNumber*stringPhone number of the contact, in international format without any whitespace/digit separators.

droneDetails

Drone details give information on the characteristics of the drone that will be undertaking the flight.

Parameter NameDatatypeDescription
colorstringThe drone's primary color.
markingsstringAny distinctive markings on the drone.
airframeairframeTypeThe airframe/performance characteristics of the drone.
weightdoubleThe weight of the drone that will be used, in kilograms.
maxWeightdoubleThe maximum take-off weight of the drone, in kilograms.

As present, there are two possible values for airframe:

ValueNameDescription
fixedWingFixed WingA craft with a rigid wing/airfoil - it generates lift through its forward airspeed.
rotaryRotaryA craft with one or more rotorblades - it generates lift through the rotation of the blades.

Validation

All requests made to this API must meet certain validation criteria as shown below.

If any of these are not met, the request will be invalid, and an HTTP response code of 400 - Bad Request will be returned.

  1. All required (*) fields must be present;
  2. All string properties have a maximum length of 255 characters, apart from firstName and lastName in pointOfContact which have a maximum of 60;
  3. pointOfContact.phoneNumber should be in international (E.123) format without whitespace/digit separators;
  4. The id of each flightPart must be unique in the context of the flight plan;
  5. Each flightPart's geography should be either a LineString, Polygon, or Point;
  6. The flight plan's total duration cannot exceed twelve (12) hours;
  7. The flight plan cannot take place more than fourteen (14) days in the future;
  8. The flight plan cannot exceed an area of 10km2;
  9. The flight plan cannot be longer than 30km.

We will continue to listen to monitor use of the service and listen to user feedback with respect to maximum area and distance limitations.

📘

Values in the request body are case in-sensitive

Values sent in the request are case-insensitive, so casing will not cause a validation error.

Create Response

Response CodeReason
200 OKSuccessful request, further details are in the body.
400 Bad RequestRequest was invalid, specific errors are detailed in the body.
401 UnauthorizedA valid API key was not present on the request.
503 Service UnavailableThe request could not be processed.

Example response body to a successful service call, indicating a conflict

{
    "operationId": "ca59943d-b6b5-4862-b883-0aaca027f6d6",
    "outcomeCode": 3000,
    "outcome": "DirectConflict",
    "conflicts": [
        {
            "severity": "DirectConflict",
            "geography": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            -0.985035,
                            51.472776
                        ],
                        [
                            -0.987803,
                            51.472094
                        ],
                        [
                            -0.984327,
                            51.471252
                        ],
                        [
                            -0.985035,
                            51.472776
                        ]
                    ]
                ]
            },
            "start": "2010-07-31T13:30:00Z",
            "end": "2010-07-31T13:45:00Z",
            "description": "Flightplan conflicts with an existing flightplan between 2010-07-31T13:30:00Z and 2010-07-31T13:45:00Z"
        }
    ]
}

Note: the description property provides a human-readable description of the conflict and the time-window in which the conflict is expected to occur (the dates and times are all in UTC). The start and end property contain just the DateTime values, if you wish to use these programatically.

Successful response with no conflict indicated:

{
    "operationId": "0d251e61-d43b-4deb-8d91-658397e7e874",
    "flightPlanId": "d31094b0-3ab5-4b0d-97c7-d5b642c56f6c",
    "outcomeCode": 1000,
    "outcome": "NoConflictingReportsFound",
    "conflicts": []
}

🚧

The outcomeCode of 1000 indicates that we could not find any other conflicting flight reports in our system. That doesn't mean that somebody else won't be operating their drone or flying nearby! When implementing this feature for your external users, you should ensure that they are fully aware that this is not an 'all clear', and we draw your attention to the Terms of Service for this API which require that you inform your users of the service's characteristics and limitations.

Definition of response properties

Parameter NameDatatypeDescription
operationIdguidA unique identifier for the request that was made.
flightPlanIdguidA unique identifier for the flight plan, which is only issued if there are no DirectConflicts.
outcomeCodeintA numeric code to describe the overall status of the flight plan.
outcomestringA human-readable description of outcomeCode.
conflictsconflict[]An array describing precisely what conflicts we have detected with your submission, if any.

A single conflict represents an intersection with another flight plan spatially and temporally, and describes the specific aspects where the conflict occurs.

Parameter NameDatatypeDescription
severitystringA description of the level of conflict.
geographygeoJSONThe area where there is a conflict.
startdateTimeThe time window during which the conflict is anticipated to exist.
enddateTimeThe time at which the conflict is expected to pass.
descriptionstringA human-readable description of the conflict.

🚧

The service assumes that people comply with their own flight plans.

By it's very nature, any service operating pre-flight for "strategic separation" must rely on the data submitted to it. Because the flights have not actually taken place yet, the service must treat the information submitted "as if" they will be faithfully executed. To help mitigate the risk of providing false positives, we apply "padding" and "buffering" in both time and space, but this process alone does not provide any guarantee that a particular flight at any given time and location will be free from conflict, or indeed conflict with any other air traffic.

Outcome/Severity is description of the extent of the overlap we have detected.

Current possible values are:

CodeNameDescription
1000NoConflictingReportsFoundNo conflicting reports exist in our network.
2000ProximityWarningYour flight is expected to come close, but not into direct contact, with at least one other flight.
3000DirectConflictYour flight is expected to come into direct conflict with at least one other flight.

Conflict Resolution Scope

The use of the conflictResolutionScope (local or global) sent as part of the submitted flight plan is to allow selection of the comprehensiveness of conflict detection process:

  • global scope means that the flight plan will be evaluated for conflicts against all other flight plans available in our network;
  • local scope means that the flight plan will only be evaluated for conflict against flight plans that originate from the same account. Other global flights will still be deconflicted against these local plans.

Draft Flight Plans

Flight plans can be submitted with isDraft set to true to perform a "what-if" operation. These flight plans permit one to query the system, but even if there is no conflict, the service won't store the flight plan.

Invalid Request

Requests that arrive in an invalid format will receive a 400 Bad Request response with the specific errors detailed in the request body keyed by the JSONPath of the erroneous field. For example:

{
    "flightPlanRequest.Summary": {
        "errors": [
            {
                "errorMessage": "'Summary' should not be empty."
            }
        ]
    },
    "flightPlanRequest.Parts[1].Start": {
        "errors": [
            {
                "errorMessage": "Start time cannot be in the past."
            }
        ]
    },
    "flightPlanRequest.Parts": {
        "errors": [
            {
                "errorMessage": "Flight Part IDs must be unique."
            },
            {
                "errorMessage": "Flight plan duration must be less than 12 hours."
            }
        ]
    }
}

In this case, the errors are:

  • The summary field is missing;
  • The second flight part has a start time in the past;
  • There are flight part IDs that share IDs;
  • The duration of the flight provided by the flight parts is greater than twelve hours.

The individual fields that error (in this case; summary, and the second flight part) will be mapped to specifically, while errors that occur over a set of fields (in this case; the flight parts) will be mapped to the set itself.

Cancel a Flight Plan

It's good practice to 'de-register' your flight plan if you no longer intend to take the flight. Doing so clears the route you were expecting to take for others to transit.

📘

Flight plans are immutable

You cannot submit a change to a flight plan. You may only cancel it, and then resubmit an altered or updated one. Note that at the point of re-submission, your flight plan will be treated as a new flight plan, and will therefore be evaluated as such.

Example of a cancellation request

POST https://flight.altitudeangel.com/v1/conflict-resolution/strategic/flight-plans/{flightPlanId}/cancel
Authorization: X-AA-ApiKey YOUR_API_KEY
Parameter NameDatatypeDescription
flightPlanId*guidThe ID of the flight plan to be cancelled.

Cancel Response

{
    "operationId": "9c516ab5-bfc9-4dc6-96a3-dffa37c501d5",
    "flightPlanId": "d31094b0-3ab5-4b0d-97c7-d5b642c56f6c",
    "message": "The flightplan has been cancelled."
}

Definition of response properties

Parameter NameDatatypeDescription
operationIdguidA unique identifier for the request that was made.
flightPlanIdguidThe ID of the flight plan that was cancelled.
messagestringA human-readable description the outcome of the request.