Files
spothole/webassets/apidocs/openapi.yml
2025-10-02 12:17:42 +01:00

595 lines
21 KiB
YAML

openapi: 3.0.4
info:
title: (S)pothole API
description: |-
(S)pothole is a utility to aggregate "spots" from amateur radio DX clusters and xOTA spotting sites, and provide an open JSON API as well as a website to browse the data.
While there are other web-based interfaces to DX clusters, and sites that aggregate spots from various outfoor activity programmes for amateur radio, (S)pothole differentiates itself by supporting a large number of data sources, and by being "API first" rather than just providing a web front-end. This allows other software to be built on top of it. (S)pothole itself is also open source, Public Domain licenced code that anyone can take and modify.
contact:
email: ian@ianrenton.com
license:
name: The Unlicense
url: https://unlicense.org/#the-unlicense
version: 0.1
servers:
- url: https://spothole.m0trt.radio/api
paths:
/spots:
get:
tags:
- spots
summary: Retrieve a set of spots.
description: The main API call that retrieves spots from the system. Supply this with no query parameters to retrieve all spots known to the system. Supply query parameters to filter what is retrieved.
operationId: spots
parameters:
- name: limit
in: query
description: Limit the number of spots in the response
required: false
schema:
type: integer
- name: since
in: query
description: Limit the spots to only ones at this time or later. Time in UTC seconds since UNIX epoch. Equivalent to "max_age" but saves the client having to work out how many seconds ago "midnight" was.
required: false
schema:
type: integer
- name: max_age
in: query
description: Limit the spots to only ones received in the last 'n' seconds. Equivalent to "since" but saves the client having to work out what time was 'n' seconds ago on every call. Refer to the "max_spot_age" in the /options call to figure out what the maximum useful value you can provide is. Larger values will still be accepted, there just won't be any spots in the system older than max_spot_age.
required: false
schema:
type: integer
- name: received_since
in: query
description: Limit the spots to only ones that the system found out about at this time or later. Time in UTC seconds since UNIX epoch. If you are using a front-end that tracks the last time it queried the API and requests spots since then, you want *this* version of the query parameter, not "since", because otherwise it may miss things. The logic is "greater than" rather than "greater than or equal to", so you can submit the time of the last received item back to this call and you will get all the more recent spots back, without duplicating the previous latest spot.
required: false
schema:
type: integer
- name: source
in: query
description: "Limit the spots to only ones from one or more sources. To select more than one source, supply a comma-separated list."
required: false
schema:
type: string
enum:
- POTA
- SOTA
- WWFF
- WWBOTA
- GMA
- HEMA
- ParksNPeaks
- Cluster
- RBN
- APRS-IS
- name: sig
in: query
description: "Limit the spots to only ones from one or more Special Interest Groups. To select more than one SIG, supply a comma-separated list."
required: false
schema:
type: string
enum:
- POTA
- SOTA
- WWFF
- WWBOTA
- GMA
- HEMA
- name: band
in: query
description: "Limit the spots to only ones from one or more bands. To select more than one band, supply a comma-separated list."
required: false
schema:
type: string
enum:
- 160m
- 80m
- 60m
- 40m
- 30m
- 20m
- 17m
- 15m
- 12m
- 10m
- 6m
- 4m
- 2m
- 70cm
- 23cm
- 13cm
- name: mode
in: query
description: "Limit the spots to only ones from one or more modes. To select more than one mode, supply a comma-separated list."
required: false
schema:
type: string
enum:
- CW
- PHONE
- SSB
- USB
- LSB
- AM
- FM
- DV
- DMR
- DSTAR
- C4FM
- M17
- DIGI
- DATA
- FT8
- FT4
- RTTY
- SSTV
- JS8
- HELL
- BPSK
- PSK
- BPSK31
- OLIVIA
- name: mode_type
in: query
description: "Limit the spots to only ones from one or more mode families. To select more than one mode family, supply a comma-separated list."
required: false
schema:
type: string
enum:
- CW
- PHONE
- DATA
- name: dx_continent
in: query
description: "Limit the spots to only ones where the DX (the operator being spotted) is on the given continent(s). To select more than one continent, supply a comma-separated list."
required: false
schema:
type: string
enum:
- EU
- NA
- SA
- AS
- AF
- OC
- AN
- name: de_continent
in: query
description: "Limit the spots to only ones where the spotteris on the given continent(s). To select more than one continent, supply a comma-separated list."
required: false
schema:
type: string
enum:
- EU
- NA
- SA
- AS
- AF
- OC
- AN
responses:
'200':
description: Successfully retrieved spots.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Spot'
/status:
get:
tags:
- status
summary: Retrieve the server status.
description: Query information about the server for use in a diagnostics display
operationId: status
responses:
'200':
description: Successfully retrieved status.
content:
application/json:
schema:
type: object
properties:
"software-version":
type: string
description: The version number of the software.
example: "1.0.1"
"server-owner-callsign":
type: string
description: The callsign of this server's operator.
example: "M0TRT"
"uptime":
type: string
description: The amount of time the software has been running for.
example: "12:34:56"
"mem_use_mb":
type: number
description: The amount of memory the software is using, in megabytes.
example: 123.456
"num_spots":
type: integer
description: Number of spots currently in the system.
example: 123
"cleanup":
type: object
properties:
status:
type: string
description: The status of the cleanup thread
example: OK
last_ran:
type: string
description: The last time the cleanup operation ran
example: 2025-09-28T20:31:00+00:00
"webserver":
type: object
properties:
status:
type: string
description: The status of the web server
example: OK
last_page_access:
type: string
description: The last time a page was accessed on the web server
example: 2025-09-28T20:31:00+00:00
last_api_access:
type: string
description: The last time an API endpoint was accessed on the web server
example: 2025-09-28T20:31:00+00:00
providers:
type: array
description: An array of all the data providers.
items:
$ref: '#/components/schemas/ProviderStatus'
/options:
get:
tags:
- spots
summary: Retieve a list of options for various enumerations.
description: Retrieves the list of options for various enumerated types, which can be found in the spots and also provided back to the API as query parameters. While these enumerated options are defined in this spec anyway, providing them in an API call allows us to define extra parameters, like the colours associated with bands, and also allows clients to set up their filters and features without having to have internal knowledge about, for example, what bands the server knows about.
operationId: options
responses:
'200':
description: Successfully retrieved options.
content:
application/json:
schema:
type: object
properties:
bands:
type: array
description: An array of all the supported bands.
items:
$ref: '#/components/schemas/Band'
modes:
type: array
description: An array of all the supported modes.
items:
type: string
example: "LSB"
mode_types:
type: array
description: An array of all the supported mode types.
items:
type: string
example: "PHONE"
sigs:
type: array
description: An array of all the supported Special Interest Groups.
items:
type: string
example: "POTA"
sources:
type: array
description: An array of all the supported data sources (providers).
items:
type: string
example: "Cluster"
continents:
type: array
description: An array of all the supported continents.
items:
type: string
example: "EU"
max_spot_age:
type: integer
description: The maximum age, in seconds, of any spot before it will be deleted by the system. When querying the /api/spots endpoint and providing a "max_age" or "since" parameter, there is no point providing a number larger than this, because the system drops all spots older than this.
example: 3600
components:
schemas:
Spot:
type: object
properties:
guid:
type: string
description: Globally unique identifier to distinguish this spot from any others.
example: d8a3f1b6-cb73-464e-b717-54b7004aa04f
dx_call:
type: string
description: Callsign of the operator that has been spotted
example: M0TRT
de_call:
type: string
description: Callsign of the operator that has spotted them
example: M0TEST
dx_name:
type: string
description: Name of the operator that has been spotted
example: Ian
dx_country:
type: string
description: Country of the DX operator
example: United Kingdom
de_country:
type: string
description: Country of the spotter
example: United Kingdom
dx_flag:
type: string
description: Country flag of the DX operator
example: ""
de_flag:
type: string
description: Country flag of the spotter
example: ""
dx_continent:
type: string
description: Continent of the DX operator
enum:
- EU
- NA
- SA
- AS
- AF
- OC
- AN
example: EU
de_continent:
type: string
enum:
- EU
- NA
- SA
- AS
- AF
- OC
- AN
description: Continent of the spotter
example: EU
dx_dxcc_id:
type: integer
description: DXCC ID of the DX operator
example: 235
de_dxcc_id:
type: integer
description: DXCC ID of the spotter
example: 235
dx_cq_zone:
type: integer
description: CQ zone of the DX operator
example: 27
dx_itu_zone:
type: integer
description: ITU zone of the DX operator
example: 14
dx_aprs_ssid:
type: string
description: If this is an APRS spot, what SSID was the DX operator using?
example: ""
mode:
type: string
description: Reported mode.
enum:
- CW
- PHONE
- SSB
- USB
- LSB
- AM
- FM
- DV
- DMR
- DSTAR
- C4FM
- M17
- DIGI
- DATA
- FT8
- FT4
- RTTY
- SSTV
- JS8
- HELL
- BPSK
- PSK
- BPSK31
- OLIVIA
example: SSB
mode_type:
type: string
description: Inferred mode "family".
enum:
- CW
- PHONE
- DATA
example: PHONE
mode_source:
type: string
description: Where we got the mode from. If this was from the spot itself, it's likely quite accurate, but if we had to fall back to the bandplan, it might not be correct.
enum:
- SPOT
- COMMENT
- BANDPLAN
- NONE
freq:
type: number
description: Frequency, in kHz
example: 7150.5
band:
type: string
description: Band, defined by the frequency.
enum:
- 160m
- 80m
- 60m
- 40m
- 30m
- 20m
- 17m
- 15m
- 12m
- 10m
- 6m
- 4m
- 2m
- 70cm
- 23cm
- 13cm
- Unknown
example: 40m
time:
type: string
description: Time of the spot, ISO 8601 format
example: 2025-09-28T19:12:41Z
received_time:
type: string
description: Time that this software received the spot, ISO 8601 format. This is used with the "since_received" call to our API to receive all data that is new to us, even if by a quirk of the API it might be older than the list time the client polled the API.
example: 2025-09-28T19:12:41Z
comment:
type: string
description: Comment left by the spotter, if any
example: "59 in NY 73"
sig:
type: string
description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
enum:
- POTA
- SOTA
- WWFF
- WWBOTA
- GMA
- HEMA
example: POTA
sig_refs:
type: array
items:
type: string
description: SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
example: GB-0001
sig_refs_names:
type: array
items:
type: string
description: SIG reference names
example: Null Country Park
activation_score:
type: integer
description: Activation score. SOTA only
example: 0
icon:
type: string
descripton: Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
example: tree
grid:
type: string
description: Maidenhead grid locator for the spot. This could be from a geographical reference e.g. POTA, or just from the country
example: IO91aa
latitude:
type: number
description: Latitude, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
example: 51.2345
longitude:
type: number
description: Latitude, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
example: -1.2345
location_source:
type: string
description: Where we got the location (grid/latitude/longitude) from. If this was from the spot itself, it's likely quite accurate, but if we had to fall back to QRZ lookup, or even a location based on the DXCC itself, it will be a lot less accurate.
enum:
- SPOT
- QRZ
- DXCC
- NONE
example: SPOT
location_good:
type: boolean
description: Does the software think the location is good enough to put a marker on a map? This is true if the source is "SPOT", or alternatively if the source is "QRZ" and the callsign doesn't have a slash in it (i.e. operator likely at home).
example: true
qrt:
type: boolean
description: QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments.
example: false
source:
type: string
description: Where we got the spot from.
enum:
- POTA
- SOTA
- WWFF
- WWBOTA
- GMA
- HEMA
- ParksNPeaks
- Cluster
- RBN
- APRS-IS
example: POTA
source_id:
type: string
description: The ID the source gave it, if any.
example: "GUID-123456"
ProviderStatus:
type: object
properties:
name:
type: string
description: The name of the provider.
example: POTA
enabled:
type: boolean
description: Whether the provider is enabled or not.
example: true
status:
type: string
description: The status of the provider.
example: OK
last_updated:
type: string
description: The last time at which this provider received data.
example: 2025-09-28T20:31:00+00:00
last_spot:
type: string
description: The time of the latest spot received by this provider.
example: 2025-09-28T20:31:00+00:00
Band:
type: object
properties:
name:
type: string
description: The name of the band
example: 40m
start_freq:
type: int
description: The start frequency of this band, in kHz.
example: 7000
end_freq:
type: int
description: The end frequency of this band, in kHz.
example: 7200
color:
type: string
description: The color associated with this mode, as used on PSK Reporter.
example: "#5959ff"
contrast_color:
type: string
description: Black or white, whichever provides the best contrast against the band colour.
example: white