The CQGMA Spot API provides recent GMA and WWFF spots as JSON data.
It is intended for lightweight clients, dashboards, tools, spot displays and integrations.
Please use the API fairly. The service is provided by CQGMA.org and should not be polled more often than once per minute.
| Purpose | URL |
|---|---|
| Last 10 spots | https://www.cqgma.org/api/spots/10/ |
| Last 25 spots | https://www.cqgma.org/api/spots/25/ |
| Last WWFF spots | https://www.cqgma.org/api/spots/wwff/?key=GMA-1234-XXXXXXXXXX |
| Last GMA-only spots | https://www.cqgma.org/api/spots/gma/ |
The main WWFF endpoint is:
https://www.cqgma.org/api/spots/wwff/?key=GMA-1234-XXXXXXXXXX
This endpoint returns the current WWFF spot list as JSON.
The data is generated server-side from a cache file. The cache file is normally refreshed once per minute.
The WWFF spot endpoint requires a valid API key.
API keys can be requested via cqGMA support:
https://www.cqgma.org/support/contact.html
The API key can be supplied as URL parameter:
https://www.cqgma.org/api/spots/wwff/?key=GMA-1234-XXXXXXXXXX
or as HTTP header:
X-API-Key: GMA-1234-XXXXXXXXXX
Example API key format:
GMA-1234-XXXXXXXXXX
Please do not poll the API more often than once per minute.
Limits:
Maximum rate: 1 request per 60 seconds
Maximum daily requests: 1440 requests per client per UTC day
The daily limit includes all requests, including requests that receive a 429 Too Many Requests response.
This means that aggressive polling will use up the daily request limit quickly, even if many of the requests are blocked.
API responses are cacheable for 60 seconds.
Clients should respect these HTTP headers:
Cache-Control: public, max-age=60
Expires: ...
Last-Modified: ...
ETag: ...
Recommended client behavior:
1. Poll no more than once per minute.
2. Respect Retry-After after receiving 429 Too Many Requests.
3. Use HTTP caching with ETag and Last-Modified where possible.
4. Avoid parallel requests from the same IP address or same API key.
5. Do not request the same endpoint repeatedly in short intervals.
Responses may include headers such as:
X-RateLimit-Limit: 1440
X-RateLimit-Remaining: 1439
Retry-After: 60
If the request rate is too high, the server returns:
HTTP/1.1 429 Too Many Requests
{
"ok": false,
"error": "missing_api_key",
"message": "An API key is required for this API.",
"source": "CQGMA WWFF API",
"website": "https://www.cqgma.org"
}
{
"ok": false,
"error": "invalid_api_key",
"message": "The supplied API key is invalid or inactive.",
"source": "CQGMA WWFF API",
"website": "https://www.cqgma.org"
}
{
"ok": false,
"error": "rate limit exceeded",
"message": "Please request CQGMA spots not more than once per minute.",
"retry_after_seconds": 42,
"limit_per_day": 1440,
"remaining_today": 1438,
"source": "CQGMA Spot API",
"website": "https://www.cqgma.org",
"info": "Free GMA and WWFF spot service provided by CQGMA.org. Please avoid excessive polling."
}
{
"ok": false,
"error": "daily limit exceeded",
"message": "Maximum 1440 spot requests per day allowed. This limit includes successful and blocked requests.",
"limit_per_day": 1440,
"reset": "00:00 UTC",
"source": "CQGMA Spot API",
"website": "https://www.cqgma.org",
"info": "Free GMA and WWFF spot service provided by CQGMA.org. Please use one request per minute maximum."
}
The exact JSON fields can change slightly depending on endpoint and spot type.
Common top-level fields:
| Field | Description |
|---|---|
| SOURCE | Source name of the feed |
| RECORDS | Number of returned spot records |
| TIMESTAMP | Unix timestamp of the feed generation |
| RCD | Array containing the spot records |
Common spot fields:
| Field | Description |
|---|---|
| DATE | Spot date |
| TIME | Spot time |
| SPOTTER | Callsign of the spotter |
| ACTIVATOR | Callsign of the activator |
| REF | Reference, for example GMA or WWFF reference |
| NAME | Name of the reference, summit, park or location |
| LAT | Latitude |
| LON | Longitude |
| MODE | Operating mode |
| QRG | Frequency |
| TEXT | Additional spot text or comment |
This example reads the WWFF spot feed using an API key.
<?php
// ------------------------------------------------------------
// PHP example: read WWFF JSON feed from CQGMA Spot API
// ------------------------------------------------------------
function GetWWFFjson($key)
{
$url = "https://www.cqgma.org/api/spots/wwff/?key=" . urlencode($key);
$stream = stream_context_create(array(
'http' => array(
'timeout' => 30
)
));
$json = file_get_contents($url, false, $stream);
if ($json === false) {
echo "Could not read CQGMA WWFF spot feed.";
return;
}
$data = json_decode($json, true);
if (!is_array($data)) {
echo "Invalid JSON received.";
return;
}
echo htmlspecialchars($data["SOURCE"]) . "<br>" . PHP_EOL;
echo htmlspecialchars($data["RECORDS"]) . "<br>" . PHP_EOL;
echo date('d/m/Y H:i:s', $data["TIMESTAMP"]) . "<br>" . PHP_EOL;
}
$key = "GMA-1234-XXXXXXXXXX";
GetWWFFjson($key);
?>
This example reads the last 10 GMA spots and displays them in a simple HTML table.
<?php
// ------------------------------------------------------------
// PHP example: read JSON feed from CQGMA Spot API
// ------------------------------------------------------------
function GetGMAjson()
{
$url = "https://www.cqgma.org/api/spots/10/";
$stream = stream_context_create(array(
'http' => array(
'timeout' => 30
)
));
$json = file_get_contents($url, false, $stream);
if ($json === false) {
echo "Could not read CQGMA spot feed.";
return;
}
$data = json_decode($json, true);
if (!is_array($data)) {
echo "Invalid JSON received.";
return;
}
echo htmlspecialchars($data["SOURCE"]) . "<br>" . PHP_EOL;
echo htmlspecialchars($data["RECORDS"]) . "<br>" . PHP_EOL;
echo date('d/m/Y H:i:s', $data["TIMESTAMP"]) . "<br>" . PHP_EOL;
echo "<table border='1'>" . PHP_EOL;
foreach ($data["RCD"] as $spot) {
echo "<tr>";
echo "<td>" . htmlspecialchars($spot["DATE"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["TIME"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["SPOTTER"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["ACTIVATOR"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["REF"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["NAME"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["LAT"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["LON"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["MODE"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["QRG"]) . "</td>" . PHP_EOL;
echo "<td>" . htmlspecialchars($spot["TEXT"]) . "</td>" . PHP_EOL;
echo "</tr>" . PHP_EOL;
}
echo "</table>" . PHP_EOL;
}
GetGMAjson();
?>
Please do not disable SSL certificate verification in production clients.
Older example code sometimes used disabled SSL verification for quick testing. For production tools, normal certificate verification should remain enabled.
If your client supports conditional requests, use ETag and Last-Modified to avoid unnecessary downloads.
For the WWFF endpoint, always send your API key either as key URL parameter or as X-API-Key HTTP header.
CQGMA website:
https://www.cqgma.org/support/contact.html