AWT Public API Documentation

Welcome to the Africa Wildlife Tracking (AWT) Public API documentation. This API provides programmatic access to wildlife tracking data from AWT devices, enabling you to integrate real-time animal tracking capabilities into your applications.

Base URL: https://api-next.africawildlifetracking.com/v2

Key Features

  • Real time and historical data of GPS tracking devices
  • Support for standard LoRa network formats (TTN, Chirpstack, Actility)
  • Device management and monitoring
  • Archive data access
  • RESTful design with JSON responses

Getting Started

  1. Contact AWT support to obtain an API key
  2. Authenticate with your API key and credentials to obtain a bearer token
  3. Use the bearer token with your API key for all subsequent requests
  4. Refresh your token at least once per hour
Important: Please adhere to the Fair Usage Policy defined by the rate limits for each endpoint. Bearer tokens must be refreshed at least once per hour.

Response Format

All API responses are returned in JSON format. The API uses conventional HTTP response codes to indicate success or failure.

Authentication

The AWT API uses a two-step authentication process combining API keys and bearer tokens for secure access.

Step 1: Obtain Bearer Token

First, authenticate with your API key and user credentials to obtain a bearer token. This token is valid for 1 hour and must be refreshed regularly.

POST /token

Retrieve a new session token for authorization.

⚠️ Rate limit: 1 request per minute

Authentication Headers

X-API-KEY: your_api_key_here Authorization: Basic base64(username:password)

Request Example

curl -X POST https://api-next.africawildlifetracking.com/v2/token \ -H "X-API-KEY: your_api_key_here" \ -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ="

Response

{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": "1h", "token_type": "Bearer" }

Step 2: Use Bearer Token

Include both your API key and the bearer token in all subsequent requests.

Request Headers

X-API-KEY: your_api_key_here Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... Content-Type: application/json
Security Best Practices:
  • Never expose your API key in client-side code or public repositories
  • Refresh your bearer token before it expires (at least once per hour)
  • Contact AWT support to rotate your API keys if needed
  • Use HTTPS for all API requests

Devices

Manage and retrieve information about tracking devices associated with your account.

GET /devices

Retrieve a complete list of all tags (devices) associated with your account.

⚠️ Rate limit: 1 request per minute

Response Example

[ { "tag_id": "1337", "imei": "A0C9B00000794AB5", "device_type": "LoRA", "asset": "Savannah Elephant", "software_version": 70, "created_at": 1577836800 } ]

Response Fields

Field Type Description
tag_id string Unique identifier of the AWT tag/device
imei string Unique identifier of the modem
device_type string Type of modem (e.g., "LoRA")
asset string Type of asset/animal being tracked
software_version integer Software version on the device
created_at integer Start date of manufacture (epoch seconds)

Tracking Data

Access real-time and historical tracking data from your devices. The API provides multiple endpoints optimized for different use cases.

Latest Data (24 Hours)

GET /data/latest

Retrieve the latest tracking data for all tags, covering up to 24 hours back or since the previous request.

⚠️ Rate limit: 1 request every 10 seconds

Note: This endpoint filters by inserted_at (when the record was inserted into the database), not the reading timestamp.

Recent Data (90 Days)

GET /data

Retrieve paginated tracking data for all tags, up to 90 days back. Returns up to 1000 records per request.

⚠️ Rate limit: 1 request every 30 seconds (shared with /data/{tagId})

Query Parameters

Parameter Type Required Description
start integer Optional Start timestamp (epoch seconds). Filters by inserted_at. Defaults to 90 days ago.
end integer Optional End timestamp (epoch seconds). Filters by inserted_at. Defaults to current time.
offset integer Optional Number of records to skip for pagination
GET /data/{tagId}

Retrieve paginated tracking data for a specific tag, up to 90 days back. Returns up to 1000 records per request.

⚠️ Rate limit: 1 request every 30 seconds (shared with /data)

Path Parameters

Parameter Type Description
tagId integer The unique tag/device ID

Archive Data

GET /data/archive

Retrieve paginated archive tracking data for all tags. Returns up to 50,000 records per request.

⚠️ Rate limit: 1 request every 30 seconds (shared with /data/archive/{tagId})

Important: Archive endpoints filter by the timestamp field (actual reading time from device), not inserted_at. This allows querying historical data based on when readings were taken.

Query Parameters

Parameter Type Required Description
start integer Optional Start timestamp (epoch seconds). Filters by reading timestamp. Defaults to 2016-01-01 (1451606400).
end integer Optional End timestamp (epoch seconds). Filters by reading timestamp. Defaults to current time.
offset integer Optional Number of records to skip for pagination
GET /data/archive/{tagId}

Retrieve paginated archive tracking data for a specific tag. Returns up to 50,000 records per request.

⚠️ Rate limit: 1 request every 30 seconds (shared with /data/archive)

Response Example

[ { "recordId": "123456abc", "tagId": 1337, "softwareVersion": 70, "reportingInterval": "1_hour", "voltage": 3.67, "batteryPercentage": 66.78, "timestamp": 1583020800, "latitude": -25.730598, "longitude": 28.219429, "accelerometer": { "x": 9997, "y": 364, "z": -14998 }, "hdop": "10m", "hdopRaw": 1, "movement": true, "alarm": false, "coverage": true, "retries": 0, "speed": 10, "temperature": 24, "altitude": 1000, "lux": 2000 } ]

Utilities

Submit LoRa data from external network sources. These endpoints support multiple LoRa network formats for flexibility in data integration.

Note: These endpoints require both the X-API-KEY header and Basic Authentication (no bearer token needed).

AWT Format

POST /lora

Submit LoRa data in AWT's native format.

Request Body

{ "payload": "9300d122700162000500001c6801015f6512ca7e8933289eb1ad40a40000090911de3b8d39051822", "eui": "04C46100008F2C4F" }

TTN Format

POST /ttn-webhook

Webhook endpoint for The Things Network (TTN) format.

Request Body

{ "end_device_ids": { "dev_eui": "04C46100008F2C4F" }, "uplink_message": { "frm_payload": "base64_encoded_payload" } }

Chirpstack Format

POST /chirpstack

Webhook endpoint for Chirpstack format.

Request Body

{ "devEUI": "04C46100008F2C4F", "data": "base64_encoded_payload" }

Actility Format

POST /actility

Webhook endpoint for Actility format.

Request Body

{ "DevEUI": "04C46100008F2C4F", "payload": "base64_encoded_payload" }

Error Handling

The AWT API uses conventional HTTP response codes to indicate the success or failure of requests. Codes in the 2xx range indicate success, codes in the 4xx range indicate client errors, and codes in the 5xx range indicate server errors.

HTTP Status Codes

Code Status Description
200 OK Request successful. Returns data array (may be empty if no data matches criteria).
201 Created Resource created successfully (LoRa data endpoints).
400 Bad Request Malformed request. Check your parameters are correct.
401 Unauthorized Invalid API key or token. Token may need to be refreshed.
403 Forbidden You do not have permission to access this resource.
404 Not Found Resource not found or you do not have permission to access it.
429 Too Many Requests Rate limit exceeded. Violation of Fair Usage Policy.
500 Internal Server Error Something went wrong on our end. Try again later or contact support.

Error Response Format

All error responses follow a consistent JSON structure:

{ "error": "Descriptive error message explaining what went wrong" }

Common Error Examples

400 Bad Request

{ "error": "Malformed request. Please check your parameters are correct." }

401 Unauthorized

{ "error": "Unauthorized. Token invalid. Please refresh token." }

404 Not Found

{ "error": "Tag ID not found or you do not have permission to access this resource." }

429 Rate Limit

{ "error": "Rate limit reached - request rejected." }

Rate Limits & Fair Usage Policy

To ensure service quality and fair access for all users, the AWT API implements rate limiting on all endpoints. Please adhere to these limits to avoid service interruption.

Endpoint Rate Limits

Endpoint Rate Limit Notes
POST /token 1 request/minute Token valid for 1 hour
GET /devices 1 request/minute -
GET /data/latest 1 request/10 seconds -
GET /data 1 request/30 seconds Shared with /data/{tagId}
GET /data/{tagId} 1 request/30 seconds Shared with /data
GET /data/archive 1 request/30 seconds Shared with /data/archive/{tagId}
GET /data/archive/{tagId} 1 request/30 seconds Shared with /data/archive
Shared Rate Limits: Some endpoints share rate limit counters. For example, calling /data and /data/{tagId} both count toward the same 30-second limit.

Best Practices

  • Cache responses: Store frequently accessed data locally to reduce API calls
  • Use pagination efficiently: Request only the data you need using offset parameters
  • Implement exponential backoff: If you receive a 429 error, wait before retrying
  • Monitor usage: Track your API calls to stay within limits
  • Use appropriate endpoints: Use /data/latest for real-time updates, archive endpoints for historical analysis

Handling Rate Limit Errors

When you exceed a rate limit, the API returns a 429 Too Many Requests response:

{ "error": "Rate limit reached - request rejected." }

Implement proper error handling and retry logic with appropriate delays between requests.

Data Models

Reading Object

The primary data structure returned by tracking data endpoints.

Field Type Description
recordId string Unique identifier for this reading
tagId number Device/tag identifier
softwareVersion number Software version running on device
reportingInterval string Configured reporting interval (e.g., "1_hour")
voltage number Battery voltage in volts
batteryPercentage number Estimated battery percentage
timestamp number Reading timestamp (epoch seconds)
latitude number GPS latitude coordinate
longitude number GPS longitude coordinate
accelerometer object 3-axis accelerometer data (x, y, z)
hdop string Horizontal dilution of precision (e.g., "10m")
hdopRaw number Raw HDOP value
movement boolean Movement detected
alarm boolean Alarm status
coverage boolean Network coverage status
retries number Number of transmission retries
speed number Speed in kilometers per hour (KPH)
temperature number Temperature in degrees Celsius
altitude number Altitude in meters above sea level
lux number Ambient light level in lux
error string Error message if payload parsing failed (optional field)
Note: When the error field is present, it indicates payload parsing failed. Other fields may be null in this case.

Code Examples

Python

Authentication & Get Devices

import requests import base64 # Configuration API_KEY = "your_api_key_here" USERNAME = "your_username" PASSWORD = "your_password" BASE_URL = "https://api-next.africawildlifetracking.com/v2" # Step 1: Get bearer token def get_token(): auth_string = f"{USERNAME}:{PASSWORD}" auth_bytes = auth_string.encode('utf-8') auth_b64 = base64.b64encode(auth_bytes).decode('utf-8') headers = { "X-API-KEY": API_KEY, "Authorization": f"Basic {auth_b64}" } response = requests.post(f"{BASE_URL}/token", headers=headers) if response.status_code == 200: return response.json()["token"] else: raise Exception(f"Authentication failed: {response.json()}") # Step 2: Get devices def get_devices(token): headers = { "X-API-KEY": API_KEY, "Authorization": f"Bearer {token}", "Content-Type": "application/json" } response = requests.get(f"{BASE_URL}/devices", headers=headers) if response.status_code == 200: return response.json() else: raise Exception(f"Failed to get devices: {response.json()}") # Example usage token = get_token() devices = get_devices(token) print(f"Found {len(devices)} devices:") for device in devices: print(f" - Tag ID: {device['tag_id']}, Type: {device['device_type']}")

Get Latest Tracking Data

def get_latest_data(token): headers = { "X-API-KEY": API_KEY, "Authorization": f"Bearer {token}", "Content-Type": "application/json" } response = requests.get(f"{BASE_URL}/data/latest", headers=headers) if response.status_code == 200: return response.json() else: raise Exception(f"Failed to get data: {response.json()}") # Example usage latest_data = get_latest_data(token) print(f"Received {len(latest_data)} readings")

JavaScript / Node.js

const axios = require('axios'); const API_KEY = 'your_api_key_here'; const USERNAME = 'your_username'; const PASSWORD = 'your_password'; const BASE_URL = 'https://api-next.africawildlifetracking.com/v2'; // Get bearer token async function getToken() { const auth = Buffer.from(`${USERNAME}:${PASSWORD}`).toString('base64'); try { const response = await axios.post(`${BASE_URL}/token`, {}, { headers: { 'X-API-KEY': API_KEY, 'Authorization': `Basic ${auth}` } }); return response.data.token; } catch (error) { console.error('Authentication failed:', error.response.data); throw error; } } // Get tracking data for specific tag async function getTagData(token, tagId, start, end) { try { const response = await axios.get(`${BASE_URL}/data/${tagId}`, { headers: { 'X-API-KEY': API_KEY, 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, params: { start, end } }); return response.data; } catch (error) { console.error('Failed to get data:', error.response.data); throw error; } } // Example usage (async () => { const token = await getToken(); const data = await getTagData(token, 1337, 1609459200, 1612137600); console.log(`Received ${data.length} readings`); })();

cURL

Get Token

curl -X POST https://api-next.africawildlifetracking.com/v2/token \ -H "X-API-KEY: your_api_key_here" \ -H "Authorization: Basic $(echo -n 'username:password' | base64)"

Get Latest Data

curl -X GET https://api-next.africawildlifetracking.com/v2/data/latest \ -H "X-API-KEY: your_api_key_here" \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json"

Get Archive Data for Tag

curl -X GET "https://api-next.africawildlifetracking.com/v2/data/archive/1337?start=1609459200&end=1612137600" \ -H "X-API-KEY: your_api_key_here" \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json"