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.

Data Coverage

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).
No 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.

POST /api

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

JSON
{
  "query": "navdataSearch",
  "dev_key": "YOUR_DEV_KEY",
  "data": {
    "ident": "DENUT",
    "exact": false,
    "limit": 50
  }
}

cURL Example

cURL
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

JSON
{
  "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".
Duplicate idents

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

JavaScript
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

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 ?? []
}