Surveillance API

Overview

The Surveillance API provides a mechanism for you to 'push' aircraft surveillance data directly to Altitude Angel, which is then standardised and correlated with other information sources in our network. These position reports along with data from other sources provides a comprehensive picture of the airspace in real-time which is used by our other services such as airspace alerts and conflict resolution. Position reports are accepted from sensors which have been pre-registered and can authenticate with the API to validate their identity.

Who is this service intended for use by?

Our surveillance infrastructure is used by:

  • Drone Detection sensors
  • ATM sensors, such as RADAR
  • Software developers who wish to provide data from one, or more, connected/observed vehicles

What are the benefits of this service?

Transmission of surveillance data to the Altitude Angel platform has numerous benefits, including the ability to then consume our other services, such as the tactical conflict resolution service, by incorporating your own data. Behind-the-scenes, we 'fuse' all data received into a common pipeline, and correlate it with other sources to provide a rich, real-time data view of the sky.

Getting started

Follow the instructions in this guide to get up and running.

🚧

You'll need a developer account in order to use this service

Register for a Developer Account at https://developers.altitudeangel.com.

Once you've got your developer account setup, decide which implementation pathway you're going to follow.

The API supports both data ingest from individual sensors, and bulk data ingest from aggregated feeds. Depending on which category you fall into, there is a slightly different authentication requirement (reflecting the type of hardware used).

  1. For a single sensor or multiple sensors (individually or via an application proxy) where your sensor client application is 'intelligent' (it can make OAuth requests), you'll need to pre-register your sensor_id with us before you begin. Open a support ticket and we'll do this quickly.

  2. If you have a 'headless' sensor device (one that does not have a UI where you can log in), go to https://surveillance.altitudeangel.com/ in order to pair it.

Minimum Requirements and API Characteristics

To help you start right, please observe the following important details:

πŸ“˜

The minimium supported TLS version is 1.2

Attempting to establish a connection using TLS Version 1.0 or 1.1 will fail, and the connection will be rejected for security reasons.

πŸ‘

Base URI

The Base URI for all services quoted here is https://surveillance-api.altitudeangel.com

🚧

URIs referenced in this document are relative

The URIs referenced in this documentation are relative to the base of https://surveillance-api.altitudeangel.com, and you must use DNS to locate the service, and respect the TTL of the record. 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).

Taken note of the above? Great! Let's get started...

Authentication

Before you can use this API, you must authenticate.

To successfully authenticate, you'll need to:

  • Pre-register your sensor device(s), by contacting our support team
  • Obtain device token(s) using one of the two methods/flows described below
  • Follow the appropriate authentication flow based on your sensor device

Information on each of these steps is shown below.

Sensor Pre-Registration

All sensors must be pre-registered on our network. Once you've given us your sensors' locally unique identifiers and your own client identifier, we'll enable them so you can authorize with our API. Please contact our support team with your sensor ID and client ID for us to pre-register your sensor.

πŸ“˜

Contact our support team to pre-register your sensors

You can do this via our support portal at https://customerportal.altitudeangel.com.

Need to register a lot of sensors?

We do support bulk pre-registration, so if you have a large number of sensors you wish to use with this service, just let our friendly team know.

Device Token

A device token is an authorization token which permits access to the Surveillance API from your sensor or system.

We support two methods of obtaining a device token:

  1. For intelligent clients such as a phone application or proxy application, device tokens can be obtained by making an OAuth2 client_credentials request to our servers including your sensor ID

  2. For headless sensors with no way of provisioning a client_id and client_secret for an OAuth2 request, we support pairing.

Pairing allows for the delivery of a device token to a device via a simple HTTPS call using the sensor's local unique identifier e.g. an IMEI number or serial number (all sensors are assigned a globally-unique identifier by our network).

πŸ“˜

Use the Pairing Portal to initiate pairing for devices that can't follow the OAuth2 flow

To initiate pairing for unintelligent clients, head to the Pairing Portal at https://surveillance.altitudeangel.com.

Choosing an appropriate local identifier for your sensor(s)

You'll need to give each of your sensors their own locally-unique identifier (this should be the unique identifier of the sensor within your system). This can be any alphanumeric string up to 255 characters in length.

During pre-registration, we will generate a globally unique ID from your locally unique one that ensures the sensor ID is unique within our network. The public APIs documented here require the globally unique ID to be passed.

The globally unique ID will be contained in your device tokens.

Headless devices will need to go through the Pairing Flow while regular devices will authenticate via our Primary Authentication Flow, detailed here.

Primary authentication flow for surveillance systems

The diagram below outlines the flow by which intelligent sensors or systems will authenticate and post position reports.

3000

Pairing flow for individual surveillance sensors

The diagram below outlines the pairing flow to be used for headless sensors to obtain a device token in order to provide position reports.

3000

Obtaining a device token for a regular sensor device

Users must have pre-registered their local unique sensor IDs by creating a support ticket.

See the general Auth docs, follow the instructions under Simple User Provisioning and Authentication and request a token with the following parameters:

Parameter NameValue
client_idID of your Client set up for device flow
client_secretSecret for the above Client
grant_type"client_credentials"
scope"surveillance_api"
token_format"jwt"
device_idThe local unique sensor id you want to create a token for

This will return a standard OAuth v2 response with an access_token and refresh_token. The access_token is the token you must use to communicate with the Surveillance API.

Pairing a headless sensor device

  1. Go to https://surveillance.altitudeangel.com/pairing/start
  2. Find the device you'd like to pair, and click the Pair button
  3. Within 60 seconds, the device to be paired must POST to /v1/pairing-tokens/consume-token with its local sensor ID

Consuming Tokens

POST https://surveillance-api.altitudeangel.com/v1/pairing-tokens/consume-token?clientUniqueId=<sensor id here>
Content-Type: application/json

This endpoint does not require authentication.

clientUniqueId must be a unique string within the context of your account, i.e. the sensor's locally unique ID, and is sent via a query string parameter.

Therefore you may theoretically use very simple IDs such as "1", although in practice we'd recommend you use a string that more easily identifies your device, such as the
IMEI number of the mobile data module, MAC address, or similar.

https://surveillance.altitudeangel.com/v1/pairing-tokens/consume-token Responses

Response CodeReason
200 OKSuccessfully consumed the pairing token. See below for data structure containing your JWT Device token.
404 Not FoundA pairing request for the specified clientUniqueId could not be found.
503 Service UnavailableThe request could not be processed.

Example response:

{
    "id": "8615ace9bf1f47e78e7c8363f1688a27",
    "sensorId": "urn:aa:device:MAyOLl4t_hIzov_qwHNhtnOwP1rPp20ZqRf_gNEh0:abc123",
    "clientUniqueId": "abc123",
    "accessToken": "eyJ0 [...] iJ9.eyJ1bmlxdWVfbmFtZSI6IlVzZXIgQVBJIFBsYW4gLSBmM2VlYTFlMWFjYTc0NTU4OWNlODMxMGQ2YzBhMzFlZCIsInVybjphYTp0b2tlbl90eXBlIjoiZGV2aWNlIiwidXJuOmFhOmRldmljZV9pZCI6InVybjphYTpkZXZpY2U6TUF5T0xsNHRfaEl6b3ZfcXdITmh0bk93UDFyUHAyMFpxUmZfZ05FaDA6QXV0b1Rlc3RVc2VyRGV2aWNlMSIsImlzcyI6IkFBLkF1dGgiLCJhdWQiOiJBQSBTZXJ2aWNlcyIsImV4cCI6MTU4NDE4MTMzMCwibmJmIjoxNTg0MDk0OTMwfQ.
    rPTq [ ... ] 57CA",
    "refreshToken": "[...]",
    "expiresAt": "2020-03-14T10:22:09.3766782+00:00"
}

PairingToken

Parameter NameDatatypeDescription
idstringUnique ID of the pairing request
sensorIdstringClientUniqueId turned into a globally unique ID
clientUniqueIdstringYour sensor ID
accessTokenstringA JWT token that you can use to connect to the position-reports endpoint
refreshTokenstringRefresh token that can be used to obtain a new accessToken
expiresAtDateTimeOffsetTime when the access token expires

Sending Position reports

POST https://surveillance-api.altitudeangel.com/v1/position-reports
Authorization: Bearer <token>
Content-Type: application/json

The API receives position reports which are processed asynchronously.

A position report consists of the following key pieces of data:

  1. sensor metadata identifying the sensor for which data is submitted
  2. One (or more) positions, which specify information about objects known, or visible, to the sensor

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

Ensure that your HTTP request is authorized. To learn how to authorize your request, see Authentication section below.

Construct the payload of your HTTP request as a JSON document using UTF-8 encoding as follows:

Minimal Example

In order for the report to be processed for map view, it needs to have the following data:

{
    "positions": [
        {
            "id": "654321",
            "sourceTimeStamp": "2021-10-18T15:42:52.481Z",
            "position": {
                "lat": 52.07096461036907,
                "lon": -0.6322133544584766
            },
            "target": {
                "ids": [
                    {
                        "id": "123456",
                        "type": "SerialNumber"
                    }
                ]
            },
            "altitudes": [
                {
                    "height": 123,
                    "datum": "msl"
                }
            ],
            "groundVelocity": {
                "x": 0,
                "y": 0,
                "z": 0
            }
        }
    ]
}

Comprehensive position report example

A more complete example looks like:

{
    "sensor": {
        "id": "123456789",
        "pressure": 1013.00,  
        "sensorPosition": {},
        "additionalInfo": {}
    },
    "positions": [
        {
            "id": "3456789", 
            "sourceTimeStamp": "2020-01-01T12:00:00.111Z",
            "target": {
                "sourceId": "12345",
                "type": "aa:target:aircraft",
                "confidence": 100,
                "ids": [{
                    "id": "UAV1111",
                    "type": "icao"
                }],
                "additionalInfo": {}
            },
            "position": {
                "lat": 0.1111,
                "lon": 51.111,
                "accuracy": 4,  
                "source": "gps",
                "age": 5
            },
            "altitudes": [{
                "height": 1234.456,
                "datum": "msl",
                "accuracy": 20,
                "source": "",
                "age": 5
            }],
            "onGround": true,
            "groundVelocity": {
                "x": 12.3,
                "y": 10.2,
                "z": 0,
                "horizontalAccuracy": 1,
                "verticalAccuracy": 1,
                "source": "",
                "age": 5
            },
            "trueAirspeed": {
                "x": 13.1,
                "y": 12.1,
                "z": 1,
                "horizontalAccuracy": 1,
                "verticalAccuracy": 1,
                "source": "",
                "age": 5
            },
            "acceleration": {
                "x": 1.1,
                "y": -0.9,
                "z": 0,
                "horizontalAccuracy": 0.1,
                "verticalAccuracy": 0.1,
                "source": "",
                "age": 5
            },
            "heading": 90.1,
            "additionalInfo": {}
        }
    ]
}

Data Models

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

PositionReport

Parameter NameDatatypeDescription
sensorSensorStateMetadata about the sensor device providing positions
positions*PositionData[]Collection of positions. Must not be empty

PositionData

Parameter NameDatatypeDescription
id*stringUniquely identifies this specific position report by the sender
sourceTimeStamp*dateTimeIndicates when the position report was sent, according to the sensor clock, in UTC. (IAT should be accounted for by the sensor)
targetTargetContains identification details of the detected object
position*GeographicPositionContains the position of the detected object
altitudesAltitude[]Contains one or more detected altitudes for the object
groundVelocityGeographicVectorContains data for the speed (in m/s) and track of the object.
trueAirspeedGeographicVectorContains information about the true airspeed (TAS) of the object
onGroundboolTrue if the sensor considers the object to be on the ground
accelerationGeographicVectorContains acceleration information for the object
headingdoubleObject heading in degrees
additionalInfoJSONProvides any additional sensor-specific information

GeographicPosition

Parameter NameDatatypeDescription
lat*doublethe latitude in decimal degrees
lon*doublethe longitude in decimal degrees
accuracydoubleAccuracy of the position in meters. If not specified, accuracy is assumed to be the accuracy of the lat/long provided
sourcestringIndicates the source of the position data (e.g GPS)
agedoubleThe age in seconds since this data was acquired

SensorState

Parameter NameDatatypeDescription
id*stringThe locally unique identifier of the sensor providing the positions
pressuredoubleCurrent pressure in mb at the sensor's location
sensorPositionSensorPositionProvides up to date sensor position information if the sensor can move/rotate/etc.
additionalInfoJSONProvides any additional information about the current state of the sensor

SensorPosition

Parameter NameDatatypeDescription
geographicPositionGeographicPositionThe position of the sensor providing the positions
altitudeAltitudeThe altitude of the sensor. For ground-based sensors, altitude datum should be MSL
headingdoubleFor directed sensors, the direction it is facing in degrees from north
angledoubleFor directed sensors, the angle of the device in degrees from horizontal

GeographicVector

Parameter NameDatatypeDescription
xdoubleEast-West part of the vector
ydoubleNorth-South part of the vector
zdoubleUp-Down part of the vector
horizontalAccuracydoubleAccuracy of the x/y parts
verticalAccuracydoubleAccuracy of the z part
sourcedoubleThe source of the vector information
agedoubleThe age in seconds since this data was acquired

Height

Parameter NameDatatypeDescription
height*doubleThe height in meters according to the specified datum
datum*stringThe height datum. One of β€œwgs84”, β€œagl”, β€œbar”, β€œmsl”
accuracydoubleAccuracy of the height in meters
sourcestringThe source of the height data
agedoubleThe age in seconds since this data was acquired

Target

Parameter NameDatatypeDescription
sourceIdstringThe sensor's unique id for this target
typestringThe type of target detected in a urn format. One of "aa:target:aircraft" or "aa:target:drone"
confidenceintThe percentage confidence that the type has been identified correctly (1-100)
idsIdentifier[]Collection of known identifiers for this target
additionalInfoJSONAdditional information about the target, e.g. make, model

Identifier

Parameter NameDatatypeDescription
id*stringThe id value
typestringText string describing the type of identifier, (e.g. ICAO, IMEI, SerialNumber)

Validation

  1. All required (*) fields must be present
  2. The positions collection may not be empty
  3. sensor.id must be the same as the sensor ID that was used to generate your device token if specified
  4. Altitude datums must be one of the accepted values

A successful response is indicated by a 202 HTTP status code with an empty body.

Responses

Response CodeReason
202 AcceptedSuccessfully posted position report. Will be processed asynchronously.
400 Bad RequestRequest body was invalid.
401 UnauthorizedA valid authorization token was not present on the request.
403 ForbiddenThe authorization token's sensor ID did not match the sensor ID in the request body; surveillance_api scope is missing from the token
503 Service UnavailableThe request could not be processed.

Surveillance Out

🚧

Authentication

The Surveillance Out endpoints retrieve device and position report data against a known Altitude Angel user. As such it requires a bearer token. The required scope for the Surveillance Out endpoints is surveillance_api. Learn more about authentication.

The user interface for surveillance where devices can be viewed and modified is found here.

Surveillance User Interface

The user interface for surveillance gives an overview of the devices associated with your user. If you don't have any devices then please contact our support desk to add devices and get started. From the devices table there are a number of actions that can be selected ranging from: setting relay details, pairing a device and enabling/disabling storing position reports.

Position reports by default will be stored in short term storage that will allow you to view them by selecting the "View recent reports" action on the devices table. If this is not desired then this can be disabled through the "actions" menu.

Relaying Position Reports

Assigning a relay URL to a device will enable the relaying functionality. Whilst being processed by our API, your position report will also be sent to the relay given that it has been successfully set up and is in an active state.

Setting Relay Details

Updating the relay details can be completed through the surveillance UI where the relay URL will be validated. This validation will check that the URL is HTTPS, reachable and is able to return a validation code that is sent as part of a POST call. If the validation fails then the reason why will be displayed to assist the set up process.

Upon a successful validation process, received position reports for the device will begin to be relayed to the given URL. The payload model containing the position report is documented below.

{
	"name": "validate",
	"version": "1.0",
	"validationCode": "some-GUID"
}
{
	"name": "position_report",
	"version": "1.0",
	"positionReport": {...}
}

Endpoints

Get Recent Position Reports For Device

This endpoint will return a list of Position Reports (see Data Models) that have been received in the current metric window (the duration can be seen in the surveillance UI).

GET: https://surveillance.altitudeangel.com/v1/devices/{deviceId}/recent
Authorization: Bearer <token>
{
    "data": [
        {
            "receivedTimeStamp": "2022-05-19T00:00:00.00Z",
            "sensor": {...},
            "positions": [...],
            "tags": [...]
        }
    ]
}

Get All Devices

This endpoint returns a full list of all devices for your user.

GET: https://surveillance.altitudeangel.com/v1/devices
Authorization: Bearer <token>
{
    "data": [
        {
            "deviceId": "",
            "deviceCreationTimestamp": "",
            "deviceName": "",
            "positionReportMetrics": [],
            "relayDetails": {
                "url": "",
                "state": "Active",
                "failureDescription": null
            },
            "shouldStorePositionReportMetrics": true
        }      
    ]
}

Get Device By URN

Gets a device by its URN (uniform resource name).

GET: https://surveillance.altitudeangel.com/v1/devices/{deviceUrn}
Authorization: Bearer <token>
{
	"deviceId": "",
	"deviceCreationTimestamp": "",
	"deviceName": "",
	"positionReportMetrics": [],
	"relayDetails": {
		"url": "",
		"state": "Active",
		"failureDescription": null
	},
	"shouldStorePositionReportMetrics": true
}

Toggle Storing Position Reports

Toggles whether position reports should be stored. These position reports will be stored for the duration of the current metric window (the duration can be seen in the surveillance UI).

POST: https://surveillance.altitudeangel.com/v1/devices/{deviceUrn}/toggle-storing-position-reports
Authorization: Bearer <token>
Boolean value based on whether it has toggled to true or false.

Set Relay Details For Device

Updates the relay details of the device.

POST: https://surveillance.altitudeangel.com/v1/devices/{deviceId}/relay
Authorization: Bearer <token>
Content-Type: application/json
{
    "url": "",
    "state": 1 = Active, 2 = Inactive, 3 = Failed
}
{
    "deviceId": "",
    "deviceCreationTimestamp": "",
    "deviceName": "",
    "positionReportMetrics": null,
    "relayDetails": {
        "url": "",
        "state": "Inactive",
        "failureDescription": null
    },
    "shouldStorePositionReportMetrics": true
}

What’s Next

Sign up for a developer account, then create a support ticket to pre-register your devices. Pre-registration is not required for prior-authorised surveillance partners.