NavData Search API
Overview
The NavData Search API lets you look up navaids and waypoints by their identifier (ident) from the VPT navigation database. It is designed for Electronic Flight Bag (EFB) integrations that need to resolve a route element into its geographic coordinates, frequency (for navaids) and AIRAC cycle metadata.
The navdata table contains both navaids (NDB/VOR/DME,
with a tuned frequency) and waypoints (intersections
without a frequency). Records are tagged with the AIRAC
cycle and validity cyclePeriod they
belong to.
Access Requirements
This endpoint is gated by three independent checks. All three must pass:
| Requirement | Notes |
|---|---|
| User token |
Authenticated user via Bearer token (returned by
signIn / signUp). Anonymous calls
are rejected with
Authentication required.
|
| Developer Key EFB flag |
Your dev_key must have the efb flag
enabled by VPT. Otherwise the request fails with
EFB access not available for your Developer Key.
|
| Active subscription |
The user must have an active subscription of
level 1 or higher. Free / level 0 users get
This feature requires an active subscription (level 1 or
higher).
|
api_key required
Unlike most endpoints, navdataSearch does
not require an api_key in the
request body — the caller is identified solely by the user Bearer
token and the developer key.
NavData Search
Searches the navdata table by ident.
By default the search uses prefix matching (ident LIKE 'XXX%') so callers can implement autocomplete UIs. Pass
"exact": true for an equality match. Results are
ordered alphabetically by ident and capped by
limit (default 50, max 200).
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string |
Required | Must be "navdataSearch" |
dev_key |
string |
Required | Your Developer Key (must have EFB access enabled) |
data.ident |
string |
Required | Identifier to search for. 1 to 5 characters, case-insensitive (uppercased server-side). |
data.exact |
boolean |
Optional |
true = exact match on ident.
false (default) = prefix match.
|
data.limit |
integer |
Optional |
Maximum rows returned. Defaults to 50,
clamped to [1, 200].
|
Request Body
{
"query": "navdataSearch",
"dev_key": "YOUR_DEV_KEY",
"data": {
"ident": "DENUT",
"exact": false,
"limit": 50
}
}
cURL Example
curl -X POST "https://api.virtualperformancetool.com/api" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-H "X-API-Version: 1.3.6" \
-d '{
"query": "navdataSearch",
"dev_key": "YOUR_DEV_KEY",
"data": {
"ident": "BRU",
"exact": false,
"limit": 20
}
}'
Response
{
"Api_Version": "1.3.6",
"Success": true,
"query": "DENUT",
"count": 1,
"navdata": [
{
"id": 12345,
"ident": "DENUT",
"name": "DENUT",
"frequency": null,
"latitude": 51.236122,
"longitude": 3.6576,
"airway": "L610",
"cycle": "2503",
"cyclePeriod": "2025-02-20/2025-03-19",
"type": "WAYPOINT"
}
]
}
Response Fields
Top-level
| Field | Type | Description |
|---|---|---|
Success |
boolean |
true when the lookup completed. An empty result
set still returns true with
count: 0.
|
query |
string |
The raw ident value from the request (echo).
|
count |
integer |
Number of rows in navdata. |
navdata |
array |
List of matching records (see below). |
NavData Record
| Field | Type | Description |
|---|---|---|
id |
integer |
Internal database row identifier. |
ident |
string |
1–5 character identifier (e.g. DENUT,
BRU).
|
name |
string |
Long name (often equals ident for waypoints).
|
frequency |
number | null |
Frequency in MHz for navaids;
null for waypoints.
|
latitude |
number |
WGS-84 latitude in decimal degrees. |
longitude |
number |
WGS-84 longitude in decimal degrees. |
airway |
string | null |
Associated airway, when applicable. |
cycle |
string | null |
AIRAC cycle (e.g. 2503). |
cyclePeriod |
string | null |
Cycle validity range (e.g.
2025-02-20/2025-03-19).
|
type |
string |
"NAVAID" if frequency is set,
otherwise "WAYPOINT".
|
Some idents exist at multiple geographic locations. The database
unique key is
(ident, latitude, longitude), so multiple rows can be
returned for the same ident. Always disambiguate
using latitude and longitude.
Error Responses
All errors are returned with HTTP 200 and a populated
Error array on the response (standard VPT API
convention).
| Error Message | Cause |
|---|---|
Authentication required. |
Missing or invalid user Bearer token. |
EFB access not available for your Developer Key.
|
The dev_key does not have the efb
flag enabled.
|
This feature requires an active subscription (level 1 or
higher).
|
The authenticated user has no active subscription or is at level 0. |
Missing required field: ident. |
data.ident is missing or empty. |
Invalid ident: maximum length is 5 characters.
|
data.ident exceeds the 5-character schema limit.
|
Usage Examples
JavaScript/TypeScript
async function searchNavdata(ident, { exact = false, limit = 50 } = {}, token, devKey) {
const response = await fetch('https://api.virtualperformancetool.com/api', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'X-API-Version': '1.3.6'
},
body: JSON.stringify({
query: 'navdataSearch',
dev_key: devKey,
data: { ident, exact, limit }
})
});
const data = await response.json();
if (!data.Success) throw new Error(data.Error?.[0]?.Message ?? 'navdataSearch failed');
return data.navdata;
}
// Example: autocomplete on partial ident
const results = await searchNavdata('BRU', { limit: 20 }, jwtToken, devKey);
for (const wp of results) {
console.log(`${wp.ident} (${wp.type}) @ ${wp.latitude}, ${wp.longitude}`);
}
Swift
struct NavDataRecord: Codable {
let id: Int
let ident: String
let name: String
let frequency: Double?
let latitude: Double
let longitude: Double
let airway: String?
let cycle: String?
let cyclePeriod: String?
let type: String
}
struct NavDataSearchResponse: Codable {
let Success: Bool
let query: String?
let count: Int?
let navdata: [NavDataRecord]?
}
func searchNavdata(ident: String, exact: Bool = false, limit: Int = 50) async throws -> [NavDataRecord] {
let body: [String: Any] = [
"query": "navdataSearch",
"dev_key": devKey,
"data": [
"ident": ident,
"exact": exact,
"limit": limit
]
]
let response: NavDataSearchResponse = try await apiClient.post(body)
return response.navdata ?? []
}