Surveillance API


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

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


URIs referenced in this document are relative

The URIs referenced in this documentation are relative to the base of, 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...


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

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

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. Most of the public APIs documented here require the locally unique ID to be passed.

The globally unique ID will be contained in your device tokens and may be required for some API calls but this will be explicitly declared.

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.

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.

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
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
  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<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. Responses

Response CodeReason
200 OKSuccessfully consumed the pairing token. See below for data structure containing your JWT Device token.
404 Bad RequestA 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"


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

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": "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 *.


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


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


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


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


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


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


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


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


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


  1. All required (*) fields must be present
  2. The positions collection may not be empty
  3. 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.


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.
503 Service UnavailableThe request could not be processed.