$schema: "https://spec.openapis.org/oas/3.1.0" openapi: 3.1.0 info: title: Spothole API description: |- Spothole 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 outdoor activity programmes for amateur radio, Spothole 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. Spothole itself is also open source, Public Domain licenced code that anyone can take and modify. The API calls described below allow third-party software to access data from Spothole, and receive data on spots and alerts in a consistent format regardless of the data sources used by Spothole itself. Utility calls are also provided for general data lookups. Please note that the data coming out of Spothole is only as good as the data going in. People mis-hear and make typos when spotting callsigns all the time, and there are plenty of areas where Spothole's location data may be inaccurate. If you are doing something where accuracy is important, such as contesting, you should not rely on Spothole's data to fill in any gaps in your log. Spothole's source code is located at https://git.ianrenton.com/ian/spothole and the README there provides setup instructions if you would like to run your own copy. A demonstration server of Spothole is located at https://spothole.app. ## Changelog ### 1.4 * POST `/spot` now supports upstream submission to external providers such as POTA and SOTA via new `submit_upstream`, `upstream_provider`, and `upstream_credentials` request body fields. * POST `/spot` now supports Google reCaptcha and (if the site owner has set it up) now requires `captcha_token` in order to successfully submit. (This is used to lock down the submit function and prevent submission via Spothole by bots or third-party clients.) * GET `/options` now returns `spot_submit_providers`, a map of SIG names to the names of providers that support upstream spot submission for that SIG. ### 1.3 * `/solar` response now includes `ionosonde_data`, which contains ionosonde station measurements (LUF, foF2 and MUF) sourced from the GIRO Data Center as well as implied band states. * `/spots`, `/spots/stream`, `/alerts`, `/alerts/stream`, and `/lookup/call` now accept optional QRZ.com and HamQTH credentials as query parameters. When supplied, returned data is enriched with operator name, home location etc. from those services. ### 1.2 * Added `/dxstats` endpoint for inter-continent DX spot statistics. * Added `/solar` endpoint for solar and propagation conditions. * Added `solar_condition_providers` array to the `/status` response. ### 1.1 * Added Server-Sent Event API endpoints for spots and alerts. * Removed band colour and icon information from spots. * Moved activation_score from top-level in Spot and Alert to be part of the SIGRef contact: email: ian@ianrenton.com license: name: The Unlicense url: https://unlicense.org/#the-unlicense version: 1.4 servers: - url: https://spothole.app/api/v1 tags: - name: Spots description: Endpoints for retrieving and submitting spots (real-time operator sightings). - name: Alerts description: Endpoints for retrieving alerts (upcoming planned activations). - name: Propagation & DX description: Endpoints for solar conditions, propagation forecasts, and DX statistics. - name: General description: Server status and enumeration options. - name: Utilities description: Utility lookups for callsigns, SIG references, and Maidenhead grids. paths: /spots: get: tags: - Spots summary: Get 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. If QRZ.com or HamQTH credentials are supplied, returned spots will be enriched with operator name, home location etc. from those services. operationId: spots parameters: - $ref: '#/components/parameters/SpotLimit' - $ref: '#/components/parameters/SpotSince' - $ref: '#/components/parameters/SpotMaxAge' - $ref: '#/components/parameters/SpotReceivedSince' - $ref: '#/components/parameters/SpotSource' - $ref: '#/components/parameters/SpotSig' - $ref: '#/components/parameters/SpotNeedsSig' - $ref: '#/components/parameters/SpotNeedsSigRef' - $ref: '#/components/parameters/SpotBand' - $ref: '#/components/parameters/SpotMode' - $ref: '#/components/parameters/SpotModeType' - $ref: '#/components/parameters/SpotDxContinent' - $ref: '#/components/parameters/SpotDeContinent' - $ref: '#/components/parameters/SpotDedupe' - $ref: '#/components/parameters/SpotDxCallIncludes' - $ref: '#/components/parameters/SpotCommentIncludes' - $ref: '#/components/parameters/SpotTextIncludes' - $ref: '#/components/parameters/SpotNeedsGoodLocation' - $ref: '#/components/parameters/SpotAllowQrt' - $ref: '#/components/parameters/QrzUsername' - $ref: '#/components/parameters/QrzPassword' - $ref: '#/components/parameters/QrzSessionKey' - $ref: '#/components/parameters/HamqthUsername' - $ref: '#/components/parameters/HamqthPassword' - $ref: '#/components/parameters/HamqthSessionId' responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/SpotList' /spots/stream: get: tags: - Spots summary: Get spot stream description: Request a Server-Sent Event stream which will return individual spots immediately when they are added to the system. Only spots that match the provided filters will be returned. If QRZ.com or HamQTH credentials are supplied, streamed spots will be enriched with operator name, home location etc. from those services. operationId: spots-stream parameters: - $ref: '#/components/parameters/SpotSource' - $ref: '#/components/parameters/SpotSig' - $ref: '#/components/parameters/SpotNeedsSig' - $ref: '#/components/parameters/SpotNeedsSigRef' - $ref: '#/components/parameters/SpotBand' - $ref: '#/components/parameters/SpotMode' - $ref: '#/components/parameters/SpotModeType' - $ref: '#/components/parameters/SpotDxContinent' - $ref: '#/components/parameters/SpotDeContinent' - $ref: '#/components/parameters/SpotDxCallIncludes' - $ref: '#/components/parameters/SpotCommentIncludes' - $ref: '#/components/parameters/SpotTextIncludes' - $ref: '#/components/parameters/SpotNeedsGoodLocation' - $ref: '#/components/parameters/SpotAllowQrt' - $ref: '#/components/parameters/QrzUsername' - $ref: '#/components/parameters/QrzPassword' - $ref: '#/components/parameters/QrzSessionKey' - $ref: '#/components/parameters/HamqthUsername' - $ref: '#/components/parameters/HamqthPassword' - $ref: '#/components/parameters/HamqthSessionId' responses: '200': description: Success content: text/event-stream: schema: $ref: '#/components/schemas/SpotStream' /alerts: get: tags: - Alerts summary: Get alerts description: Retrieves alerts (indications of upcoming activations) from the system. Supply this with no query parameters to retrieve all alerts known to the system. Supply query parameters to filter what is retrieved. If QRZ.com or HamQTH credentials are supplied, returned alerts will be enriched with operator names from those services. operationId: alerts parameters: - $ref: '#/components/parameters/AlertLimit' - $ref: '#/components/parameters/AlertReceivedSince' - $ref: '#/components/parameters/AlertMaxDuration' - $ref: '#/components/parameters/AlertDxpeditionsSkipMaxDurationCheck' - $ref: '#/components/parameters/AlertSource' - $ref: '#/components/parameters/AlertSig' - $ref: '#/components/parameters/AlertDxContinent' - $ref: '#/components/parameters/AlertDxCallIncludes' - $ref: '#/components/parameters/AlertTextIncludes' - $ref: '#/components/parameters/QrzUsername' - $ref: '#/components/parameters/QrzPassword' - $ref: '#/components/parameters/QrzSessionKey' - $ref: '#/components/parameters/HamqthUsername' - $ref: '#/components/parameters/HamqthPassword' - $ref: '#/components/parameters/HamqthSessionId' responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/AlertList' /alerts/stream: get: tags: - Alerts summary: Get alert stream description: Request a Server-Sent Event stream which will return individual alerts immediately when they are added to the system. Only alerts that match the provided filters will be returned. If QRZ.com or HamQTH credentials are supplied, streamed alerts will be enriched with operator names from those services. operationId: alerts-stream parameters: - $ref: '#/components/parameters/AlertMaxDuration' - $ref: '#/components/parameters/AlertDxpeditionsSkipMaxDurationCheck' - $ref: '#/components/parameters/AlertSource' - $ref: '#/components/parameters/AlertSig' - $ref: '#/components/parameters/AlertDxContinent' - $ref: '#/components/parameters/AlertDxCallIncludes' - $ref: '#/components/parameters/AlertTextIncludes' - $ref: '#/components/parameters/QrzUsername' - $ref: '#/components/parameters/QrzPassword' - $ref: '#/components/parameters/QrzSessionKey' - $ref: '#/components/parameters/HamqthUsername' - $ref: '#/components/parameters/HamqthPassword' - $ref: '#/components/parameters/HamqthSessionId' responses: '200': description: Success content: text/event-stream: schema: $ref: '#/components/schemas/AlertStream' /solar: get: tags: - Propagation & DX summary: Get solar and band conditions description: Returns the current solar conditions and HF/VHF propagation condition summaries. This data is sourced from external providers (e.g. HamQSL) and updated periodically. All fields may be null if no provider has successfully fetched data yet. operationId: solar responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/SolarConditions' /dxstats: get: tags: - Propagation & DX summary: Get spot counts by continent and band description: Returns a three-level nested object of spot counts from the current spot database, grouped by DE continent, then DX continent, then band. Only spots in the last hour are counted, regardless of what the server owner has set the spot expiry time to. operationId: dxstats responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/DxStats' example: EU: NA: { 20m: 42, 17m: 7, 15m: 3, 10m: 0, 6m: 0, 160m: 0, 80m: 1, 60m: 0, 40m: 5, 30m: 2, 12m: 0 } EU: { 20m: 18, 17m: 2, 15m: 0, 10m: 0, 6m: 1, 160m: 0, 80m: 4, 60m: 0, 40m: 9, 30m: 1, 12m: 0 } /status: get: tags: - General summary: Get server status description: Query information about the server for use in a diagnostics display. operationId: status responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/ServerStatus' /options: get: tags: - General summary: Get enumeration options 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. The call also returns a variety of other parameters that may be of use to a web UI or other client. operationId: options responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/Options' /lookup/call: get: tags: - Utilities summary: Look up callsign details description: Perform a lookup of data about a certain callsign, using any of the lookup services available to the Spothole server. If QRZ.com or HamQTH credentials are supplied, the response will be able to use these services to perform a lookup. operationId: call parameters: - $ref: '#/components/parameters/CallParam' - $ref: '#/components/parameters/QrzUsername' - $ref: '#/components/parameters/QrzPassword' - $ref: '#/components/parameters/QrzSessionKey' - $ref: '#/components/parameters/HamqthUsername' - $ref: '#/components/parameters/HamqthPassword' - $ref: '#/components/parameters/HamqthSessionId' responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/CallLookup' '422': description: Validation error e.g. callsign missing or format incorrect content: application/json: schema: type: string example: "Failed" /lookup/sigref: get: tags: - Utilities summary: Look up SIG ref details description: Perform a lookup of data about a certain reference, providing the SIG and the ID of the reference. A SIGRef structure will be returned containing the SIG and ID, plus any other information Spothole could find about it. operationId: sigref parameters: - $ref: '#/components/parameters/SigRefSig' - $ref: '#/components/parameters/SigRefId' responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/SIGRef' '422': description: Validation error e.g. SIG not supported or reference format incorrect content: application/json: schema: type: string example: "Failed" /lookup/grid: get: tags: - Utilities summary: Look up grid details description: Perform a lookup of data about a Maidenhead grid square. operationId: grid parameters: - $ref: '#/components/parameters/GridParam' responses: '200': description: Success content: application/json: schema: $ref: '#/components/schemas/GridLookup' '422': description: Validation error e.g. reference format incorrect content: application/json: schema: type: string example: "Failed" /spot: post: tags: - Spots summary: Add a spot description: "Supply a new spot object, which will be added to the system. Optionally, set `submit_upstream` to true to forward the spot to an external provider such as POTA or SOTA. Check `spot_submit_providers` in the `/options` response to see which SIGs and providers support this. cURL example (local-only): `curl --request POST --header \"Content-Type: application/json\" --data '{\"dx_call\":\"M0TRT\",\"time\":1760019539, \"freq\":14200000, \"comment\":\"Test spot please ignore\", \"de_call\":\"M0TRT\"}' https://spothole.app/api/v1/spot`" operationId: spot requestBody: description: The JSON spot object, plus optional upstream submission control fields required: true content: application/json: schema: $ref: '#/components/schemas/SpotSubmission' responses: '201': description: Success content: application/json: schema: type: string example: "OK" '415': description: Incorrect Content-Type content: application/json: schema: type: string example: "Failed" '422': description: Validation error content: application/json: schema: type: string example: "Failed" '500': description: Internal server error content: application/json: schema: type: string example: "Failed" components: parameters: QrzUsername: name: qrz_username in: query description: "QRZ.com username for online callsign lookup, which will enrich the returned spots and alerts with extra data. Requires a QRZ.com XML Subscriber (paid) account. Supply together with `qrz_password`, or supply `qrz_session_key` instead." schema: type: string QrzPassword: name: qrz_password in: query description: "QRZ.com password. Supply together with `qrz_username`." schema: type: string QrzSessionKey: name: qrz_session_key in: query description: "A pre-obtained QRZ.com XML session key, as an alternative to supplying `qrz_username` and `qrz_password`. See https://www.qrz.com/docs/xml/current_spec.html for details on how to obtain one for the user." schema: type: string HamqthUsername: name: hamqth_username in: query description: "HamQTH username for online callsign lookup, which will enrich the returned spots and alerts with extra data. Supply together with `hamqth_password`, or supply `hamqth_session_id` instead." schema: type: string HamqthPassword: name: hamqth_password in: query description: "HamQTH password. Supply together with `hamqth_username`." schema: type: string HamqthSessionId: name: hamqth_session_id in: query description: "A pre-obtained HamQTH session ID, as an alternative to supplying `hamqth_username` and `hamqth_password`. See https://www.hamqth.com/developers.php for details on how to retrieve one for a user." schema: type: string SpotSource: 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." schema: $ref: "#/components/schemas/Source" SpotSig: name: sig in: query description: "Limit the spots to only ones from one or more Special Interest Groups provided as an argument. To select more than one SIG, supply a comma-separated list. The special `sig` name `NO_SIG` matches spots with no sig set. You can use `sig=NO_SIG` to specifically only return generic spots with no associated SIG. You can also use combinations to request for example POTA + no SIG, but reject other SIGs. If you want to request 'every SIG and not No SIG', see the `needs_sig` query parameter for a shortcut." schema: $ref: "#/components/schemas/SIGNameIncludingNoSIG" SpotNeedsSig: name: needs_sig in: query description: "Limit the spots to only ones with a Special Interest Group such as POTA. Because supplying all known SIGs as a `sigs` parameter is unwieldy, and leaving `sigs` blank will also return spots with *no* SIG, this parameter can be set true to return only spots with a SIG, regardless of what it is, so long as it's not blank. This is the equivalent of supplying the `sig` query param with a list of every known SIG apart from the special `NO_SIG` value. This is what Field Spotter uses to exclude generic cluster spots and only retrieve xOTA things." schema: type: boolean default: false SpotNeedsSigRef: name: needs_sig_ref in: query description: "Limit the spots to only ones which have at least one reference (e.g. a park reference) for Special Interest Groups such as POTA." schema: type: boolean default: false SpotBand: 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." schema: $ref: "#/components/schemas/BandName" SpotMode: 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." schema: $ref: "#/components/schemas/Mode" SpotModeType: 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." schema: $ref: "#/components/schemas/ModeType" SpotDxContinent: 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." schema: $ref: "#/components/schemas/Continent" SpotDeContinent: name: de_continent in: query description: "Limit the spots to only ones where the spotter is on the given continent(s). To select more than one continent, supply a comma-separated list." schema: $ref: "#/components/schemas/Continent" SpotDxCallIncludes: name: dx_call_includes in: query description: "Limit the spots to only ones where the DX callsign includes the supplied string (case-insensitive). Generally a complete callsign, but you can supply a shorter string for partial matches." schema: type: string SpotCommentIncludes: name: comment_includes in: query description: "Return only spots where the comment includes the provided string (case-insensitive)." schema: type: string SpotTextIncludes: name: text_includes in: query description: "Limit the spots to only ones where some significant text (DX callsign or comment) includes the supplied string (case-insensitive)." schema: type: string SpotNeedsGoodLocation: name: needs_good_location in: query description: "Return only spots with a 'good' location. (See the spot `dx_location_good` parameter for details. Useful for map-based clients, to avoid spots with 'bad' locations e.g. loads of cluster spots ending up in the centre of the DXCC entitity.)" schema: type: boolean default: false SpotAllowQrt: name: allow_qrt in: query description: Allow spots that are known to be QRT to be returned. schema: type: boolean default: true AlertMaxDuration: name: max_duration in: query description: Limit the alerts to only ones with a duration of this many seconds or less. Duration is end time minus start time, if end time is set, otherwise the activation is assumed to be short and therefore to always pass this check. This is useful to filter out people who alert POTA activations lasting months or even years, but note it will also include multi-day or multi-week DXpeditions that you might otherwise be interested in. See the dxpeditions_skip_max_duration_check parameter for the workaround. schema: type: integer AlertDxpeditionsSkipMaxDurationCheck: name: dxpeditions_skip_max_duration_check in: query description: Return DXpedition alerts even if they last longer than max_duration. This allows the user to filter out multi-day/multi-week POTA alerts where the operator likely won't be on the air most of the time, but keep multi-day/multi-week DXpeditions where the operator(s) likely *will* be on the air most of the time. schema: type: boolean AlertSource: name: source in: query description: "Limit the alerts to only ones from one or more sources. To select more than one source, supply a comma-separated list." schema: $ref: "#/components/schemas/Source" AlertSig: name: sig in: query description: "Limit the alerts to only ones from one or more Special Interest Groups. To select more than one SIG, supply a comma-separated list. The special value 'NO_SIG' can be included to return alerts specifically without an associated SIG (i.e. general DXpeditions)." schema: $ref: "#/components/schemas/SIGNameIncludingNoSIG" AlertDxContinent: name: dx_continent in: query description: "Limit the alerts to only ones where the DX operator is on the given continent(s). To select more than one continent, supply a comma-separated list." schema: $ref: "#/components/schemas/Continent" AlertDxCallIncludes: name: dx_call_includes in: query description: "Limit the alerts to only ones where the DX callsign includes the supplied string (case-insensitive). Generally a complete callsign, but you can supply a shorter string for partial matches." schema: type: string AlertTextIncludes: name: text_includes in: query description: "Limit the alerts to only ones where some significant text (DX callsign, freqs/modes, or comment) includes the supplied string (case-insensitive)." schema: type: string SpotLimit: name: limit in: query description: Limit the number of spots in the response schema: type: integer SpotSince: 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. schema: type: number SpotMaxAge: 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. schema: type: number SpotReceivedSince: 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. schema: type: number SpotDedupe: name: dedupe in: query description: "\"De-duplicate\" the spots, returning only the latest spot for any given callsign." schema: type: boolean default: false AlertLimit: name: limit in: query description: Limit the number of alerts in the response schema: type: integer AlertReceivedSince: name: received_since in: query description: Limit the alerts 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 alerts 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 alerts back, without duplicating the previous latest spot. schema: type: number CallParam: name: call in: query description: A callsign required: true schema: type: string example: M0TRT SigRefSig: name: sig in: query description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA required: true schema: $ref: "#/components/schemas/SIGName" SigRefId: name: id in: query description: ID of a reference in that SIG required: true schema: type: string example: GB-0001 GridParam: name: grid in: query description: Maidenhead grid, to any accuracy required: true schema: type: string example: "AA00aa" schemas: Source: type: string enum: - POTA - SOTA - WWFF - WWBOTA - GMA - HEMA - ParksNPeaks - ZLOTA - WOTA - LLOTA - WWTOTA - Tiles - Cluster - RBN - APRS-IS - UKPacketNet example: POTA SIGName: type: string enum: - POTA - SOTA - WWFF - WWBOTA - GMA - HEMA - WCA - MOTA - SIOTA - ARLHS - ILLW - ZLOTA - KRMNPA - IOTA - WOTA - BOTA - LLOTA - WWTOTA - Tiles - WAB - WAI - TOTA example: POTA SIGNameIncludingNoSIG: oneOf: - $ref: "#/components/schemas/SIGName" - type: string enum: [ NO_SIG ] example: POTA Continent: type: string enum: - EU - NA - SA - AS - AF - OC - AN example: EU BandName: type: string enum: - 2200m - 600m - 160m - 80m - 60m - 40m - 30m - 20m - 17m - 15m - 12m - 11m - 10m - 6m - 5m - 4m - 2m - 1.25m - 70cm - 23cm - 2.4GHz - 5.8GHz - 10GHz - 24GHz - 47GHz - 76GHz example: 40m Mode: type: string enum: - CW - PHONE - SSB - USB - LSB - AM - FM - DV - DMR - DSTAR - C4FM - M17 - DATA - FT8 - FT4 - RTTY - SSTV - JS8 - HELL - OLIVIA - PSK - FSK - PKT - MSK144 example: SSB ModeType: type: string enum: - CW - PHONE - DATA example: CW ModeSource: type: string enum: - SPOT - COMMENT - BANDPLAN - NONE example: SPOT LocationSourceForSpot: type: string enum: - SPOT - "SIG REF LOOKUP" - "WAB/WAI GRID" - "HOME QTH" - DXCC - NONE example: SPOT LocationSourceForAlert: type: string enum: - "HOME QTH" - DXCC - NONE example: "HOME QTH" SIGRef: type: object properties: id: type: string description: SIG reference ID. example: GB-0001 sig: description: SIG that this reference is in. $ref: "#/components/schemas/SIGName" name: type: string description: SIG reference name example: Null Country Park url: type: string description: SIG reference URL, which the user can look up for more information example: "https://pota.app/#/park/GB-0001" grid: type: string description: Maidenhead grid locator for the reference, if known. example: IO91aa latitude: type: number description: Latitude of the reference, in degrees, if known. example: 51.2345 longitude: type: number description: Longitude of the reference, in degrees, if known. example: -1.2345 activation_score: type: integer description: Activation score. SOTA only example: 0 Spot: type: object properties: id: type: string description: Unique identifier based on a hash of the spot to distinguish this one from any others. example: 442c5d56ac467341f1943e8596685073b38f5a5d4c3802ca1e16ecf98967956c dx_call: type: string description: Callsign of the operator that has been spotted example: M0TRT dx_name: type: string description: Name of the operator that has been spotted example: Ian dx_qth: type: string description: QTH of the operator that has been spotted. This could be from any SIG refs or could be from online lookup of their home QTH. example: Dorset dx_country: type: string description: Country of the operator. Note that this is named "country" for commonality with other amateur radio tools, but in reality this is more of a "DXCC Name", as it includes many options which are not countries, just territories that DXCC uniquely identifies. example: England dx_flag: type: string description: Country flag of the DX operator. This is limited to the range of emoji flags. For some DXCCs there may not be an official emoji flag, e.g. Northern Ireland, so the appearance may vary depending on your browser and operating system. Some small islands may also have no flag. Many DXCCs may also share a flag, e.g. mainland Spain, Balearic Islands, etc. example: "" dx_continent: description: Continent of the DX operator $ref: "#/components/schemas/Continent" dx_dxcc_id: type: integer description: DXCC ID of the DX operator 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_ssid: type: string description: If this is an APRS/Packet/etc. spot, what SSID was the DX operator/sender using? example: "7" dx_grid: type: string description: Maidenhead grid locator for the DX spot. This could be from a geographical reference e.g. POTA, or just from the country example: IO91aa dx_latitude: type: number description: Latitude of the DX spot, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup example: 51.2345 dx_longitude: type: number description: Longitude of the DX spot, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup example: -1.2345 dx_location_source: description: Where we got the DX location (grid/latitude/longitude) from. If this was from the spot itself, or from a lookup of the SIG ref (e.g. park) 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. $ref: "#/components/schemas/LocationSourceForSpot" dx_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", "SIG REF LOOKUP" or "WAB/WAI GRID", or alternatively if the source is "HOME QTH" and the callsign doesn't have a slash in it (i.e. operator likely at home). example: true de_call: type: string description: Callsign of the operator that has spotted them example: M0TEST de_country: type: string description: Country of the operator. Note that this is named "country" for commonality with other amateur radio tools, but in reality this is more of a "DXCC Name", as it includes many options which are not countries, just territories that DXCC uniquely identifies. example: England de_flag: type: string description: Country flag of the spotter. This is limited to the range of emoji flags. For some DXCCs there may not be an official emoji flag, e.g. Northern Ireland, so the appearance may vary depending on your browser and operating system. Some small islands may also have no flag. Many DXCCs may also share a flag, e.g. mainland Spain, Balearic Islands, etc. example: "" de_continent: description: Continent of the spotter $ref: "#/components/schemas/Continent" de_dxcc_id: type: integer description: DXCC ID of the spotter example: 235 de_ssid: type: string description: If this is an APRS/Packet/etc. spot, what SSID was the receiver using? example: "9" de_grid: type: string description: Maidenhead grid locator for the spotter. This is not going to be from a xOTA reference so it will likely just be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some simple mapping. example: IO91aa de_latitude: type: number description: Latitude of the spotter, in degrees. This is not going to be from a xOTA reference so it will likely just be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some simple mapping. example: 51.2345 de_longitude: type: number description: Longitude of the DX spotspotter, in degrees. This is not going to be from a xOTA reference so it will likely just be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some simple mapping. example: -1.2345 mode: description: Reported mode. $ref: "#/components/schemas/Mode" example: SSB mode_type: description: Inferred mode "family". $ref: "#/components/schemas/ModeType" mode_source: 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. $ref: "#/components/schemas/ModeSource" freq: type: number description: Frequency, in Hz example: 7150500 band: description: Band, defined by the frequency. $ref: "#/components/schemas/BandName" time: type: number description: Time of the spot, UTC seconds since UNIX epoch example: 1759579508 time_iso: type: string description: Time of the spot, ISO 8601 example: "2025-10-05T12:34:56.789Z" received_time: type: number description: Time that this software received the spot, UTC seconds since UNIX epoch. 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: 1759579508 received_time_iso: type: string description: Time that this software received the spot, ISO 8601 example: "2025-10-05T12:34:56.789Z" comment: type: string description: Comment left by the spotter, if any example: "59 in NY 73" sig: description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA $ref: "#/components/schemas/SIGName" sig_refs: type: array items: $ref: '#/components/schemas/SIGRef' description: SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO qrt: type: boolean description: QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments. example: false source: description: Where we got the spot from. $ref: "#/components/schemas/Source" source_id: type: string description: The ID the source gave it, if any. example: "GUID-123456" SpotSubmission: description: > Request body for POST /spot. Contains all the fields of a Spot, plus optional upstream submission control fields that are consumed by the server and never stored in the spot. allOf: - $ref: '#/components/schemas/Spot' - type: object properties: submit_upstream: type: boolean description: > If true, forward the spot to an external upstream provider (e.g. POTA, SOTA) rather than only adding it to this Spothole server. Requires `sig`, at least one `sig_refs` entry, and `upstream_provider` to be set. Check `spot_submit_providers` in the /options response to see which SIGs and providers support this. default: false upstream_provider: type: string description: > Name of the upstream provider to submit the spot to, e.g. "POTA" or "SOTA". Must match one of the provider names returned in `spot_submit_providers` for the chosen SIG. example: POTA upstream_credentials: type: object description: > Provider-specific credentials required to authenticate the upstream submission. The required keys depend on the provider . Credentials are used only for the upstream call and are never stored by Spothole. additionalProperties: type: string example: user_id: "12345" api_key: "abc123" captcha_token: type: string description: > A Google reCAPTCHA v2 response token. Required when submitting upstream if the server has reCAPTCHA configured (i.e. `submit_upstream` is true and the server operator has set up reCAPTCHA keys). Obtain the token by completing the reCAPTCHA widget rendered on the Add Spot page. example: "03AFY_a8Xq..." SpotStream: type: object description: A server-sent event containing a spot required: [ data ] properties: data: $ref: "#/components/schemas/Spot" Alert: type: object properties: id: type: string description: Unique identifier based on a hash of the alert to distinguish this one from any others. example: 442c5d56ac467341f1943e8596685073b38f5a5d4c3802ca1e16ecf98967956c dx_calls: type: array description: Callsigns of the operator(s) that are going to be activating items: type: string example: M0TRT dx_names: type: array description: Names of the operator(s) that are going to be activating items: type: string example: Ian dx_country: type: string description: Country of the DX operator. Country of the operator. Note that this is named "country" for commonality with other amateur radio tools, but in reality this is more of a "DXCC Name", as it includes many options which are not countries, just territories that DXCC uniquely identifies. This, and the subsequent fields, assume that all activators will be in the same country! example: England dx_flag: type: string description: Country flag of the DX operator. This is limited to the range of emoji flags. For some DXCCs there may not be an official emoji flag, e.g. Northern Ireland, so the appearance may vary depending on your browser and operating system. Some small islands may also have no flag. Many DXCCs may also share a flag, e.g. mainland Spain, Balearic Islands, etc. example: "" dx_continent: description: Continent of the DX operator $ref: "#/components/schemas/Continent" dx_dxcc_id: type: integer description: DXCC ID of the DX operator 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 freqs_modes: type: string description: An indication of the frequencies and modes that the activation will use, if provided. example: "7-ssb 14-ssb maybe 145-fm" start_time: type: number description: Time that the activation is expected to start, UTC seconds since UNIX epoch example: 1759579508 start_time_iso: type: string description: Time that the activation is expected to start, ISO 8601 example: "2025-10-05T12:34:56.789Z" end_time: type: number description: Time that the activation is expected to star, UTC seconds since UNIX epoch example: 1759579508 end_time_iso: type: string description: Time that the activation is expected to star, ISO 8601 example: "2025-10-05T12:34:56.789Z" received_time: type: number description: Time that this software received the alert, UTC seconds since UNIX epoch. 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: 1759579508 received_time_iso: type: string description: Time that this software received the alert, ISO 8601 example: "2025-10-05T12:34:56.789Z" comment: type: string description: Comment made by the activator, if any example: "2025 DXpedition to null island" sig: description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA $ref: "#/components/schemas/SIGName" sig_refs: type: array items: $ref: '#/components/schemas/SIGRef' description: SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO source: type: string description: Where we got the alert from. $ref: "#/components/schemas/Source" source_id: type: string description: The ID the source gave it, if any. example: "GUID-123456" AlertStream: type: object description: A server-sent event containing an alert required: [ data ] properties: data: $ref: "#/components/schemas/Alert" SpotProviderStatus: type: object properties: name: description: The name of the provider. $ref: "#/components/schemas/Source" 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: number description: The last time at which this provider received data, UTC seconds since UNIX epoch. If this is zero, the spot provider has never updated. example: 1759579508 last_spot: type: number description: The time of the latest spot received by this provider, UTC seconds since UNIX epoch. If this is zero, the spot provider has never received a spot that was accepted by the system. example: 1759579508 AlertProviderStatus: type: object properties: name: description: The name of the provider. $ref: "#/components/schemas/Source" 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: number description: The last time at which this provider received data, UTC seconds since UNIX epoch. If this is zero, the alert provider has never updated. example: 1759579508 Band: type: object properties: name: description: The name of the band $ref: "#/components/schemas/BandName" start_freq: type: integer description: The start frequency of this band, in Hz. example: 7000000 end_freq: type: integer description: The end frequency of this band, in Hz. example: 7200000 SIG: type: object properties: name: description: The abbreviated name of the SIG $ref: "#/components/schemas/SIGName" description: type: string description: The full name of the SIG example: Parks on the Air ref_regex: type: string description: Regex that matches this SIG's reference IDs. Generally for Spothole's own internal use, clients probably won't need this. example: "[A-Z]{2}\\-\\d+" SolarConditions: type: object description: Current solar and propagation conditions. All fields may be null if no provider has successfully fetched data yet. properties: updated: type: number description: Time that the data was last updated, UTC seconds since UNIX epoch example: 1759579508 sfi: type: integer description: Solar Flux Index (SFI) example: 170 a_index: type: integer description: Daily geomagnetic activity index example: 7 k_index: type: integer description: 3-hour geomagnetic activity index, 0–9 example: 2 xray: type: string description: Current X-ray flux class example: "B2.3" proton_flux: type: integer description: Proton flux level example: 1 electron_flux: type: integer description: Electron flux level example: 631 aurora: type: integer description: Aurora activity level example: 5 aurora_latitude: type: number description: Lowest latitude at which aurora should be visible example: 66.3 sunspots: type: integer description: Sunspot count example: 87 solar_wind: type: number description: Solar wind speed in km/s example: 356.6 magnetic_field: type: number description: Interplanetary magnetic field strength in nT example: 2.5 geomag_field: type: string description: Geomagnetic field condition summary example: "Active" geomag_noise: type: string description: Geomagnetic background noise level on HF, in S-units example: "S0" hf_conditions: type: object description: HF propagation condition assessments, keyed by "{band}-{time}" e.g. "80m-40m-day" properties: 80m-40m-day: type: string enum: [ Good, Fair, Poor ] 80m-40m-night: type: string enum: [ Good, Fair, Poor ] 30m-20m-day: type: string enum: [ Good, Fair, Poor ] 30m-20m-night: type: string enum: [ Good, Fair, Poor ] 17m-15m-day: type: string enum: [ Good, Fair, Poor ] 17m-15m-night: type: string enum: [ Good, Fair, Poor ] 12m-10m-day: type: string enum: [ Good, Fair, Poor ] 12m-10m-night: type: string enum: [ Good, Fair, Poor ] vhf_conditions: type: object description: VHF propagation condition assessments, keyed by condition name properties: vhf_aurora_northern_hemi: type: string description: VHF aurora propagation condition for the northern hemisphere example: "Band Closed" es_2m_europe: type: string description: Sporadic-E propagation condition on 2m for Europe example: "Band Closed" es_4m_europe: type: string description: Sporadic-E propagation condition on 4m for Europe example: "Band Closed" es_6m_europe: type: string description: Sporadic-E propagation condition on 6m for Europe example: "Band Closed" es_2m_na: type: string description: Sporadic-E propagation condition on 2m for North America example: "Band Closed" k_index_forecast: type: object description: > NOAA Kp index 3-day forecast. Keys are UNIX timestamps (UTC seconds since epoch) for the start of each 3-hour period. Values are the forecast Kp index (0–9) for that period. Only forecast values are included; observed actuals (shown in parentheses in the source data) are discarded. additionalProperties: type: number minimum: 0 maximum: 9 example: "1743638400.0": 4.0 "1743649200.0": 5.67 "1743660000.0": 3.67 solar_storm_forecast: type: object description: > NOAA Solar Radiation Storm forecast containing probability (%) of S1 or greater events per day. Keys are UNIX timestamps (UTC seconds since epoch) for the start of each forecast day. Values are integer percentages (0–100). additionalProperties: type: integer minimum: 0 maximum: 100 example: "1743638400.0": 50 "1743724800.0": 50 "1743811200.0": 25 blackout_forecast_r1r2: type: object description: > NOAA Radio Blackout forecast containing probability (%) of R1–R2 (Minor–Moderate) blackout events per day. Keys are UNIX timestamps (UTC seconds since epoch) for the start of each forecast day. Values are integer percentages (0–100). additionalProperties: type: integer minimum: 0 maximum: 100 example: "1743638400.0": 55 "1743724800.0": 55 "1743811200.0": 55 blackout_forecast_r3_or_greater: type: object description: > NOAA Radio Blackout forecast containing probability (%) of R3 or greater (Strong–Extreme) blackout events per day. Keys are UNIX timestamps (UTC seconds since epoch) for the start of each forecast day. Values are integer percentages (0–100). additionalProperties: type: integer minimum: 0 maximum: 100 example: "1743638400.0": 25 "1743724800.0": 25 "1743811200.0": 25 xray_desc: type: string description: HF radio blackout risk description, derived from the X-ray flux class. example: "No significant radio blackout" radio_blackout_scale: type: integer description: HF radio blackout scale number (R0-R5), derived from the X-ray flux class. minimum: 0 maximum: 5 example: 0 proton_flux_desc: type: string description: Solar radiation storm level description, derived from proton flux. example: "No solar radiation storm" solar_storm_scale: type: integer description: Solar radiation storm scale number (S0-S5), derived from proton flux. S0 = none, S5 = extreme. minimum: 0 maximum: 5 example: 0 geomag_storm_desc: type: string description: Geomagnetic storm level description, derived from K-index. example: "Quiet" geomag_storm_scale: type: integer description: Geomagnetic storm scale number (G0-G5), derived from K-index. G0 = none, G5 = extreme. minimum: 0 maximum: 5 example: 0 band_conditions_desc: type: string description: Overall HF band conditions summary, derived from Solar Flux Index. example: "Fair to good conditions on all bands up to 10m" electron_flux_desc: type: string description: Electron flux impact description, derived from electron flux level. example: "No impact" ionosonde_data: type: object nullable: true description: > Ionosonde measurements from the GIRO Data Center, keyed by URSI station code. All known stations are included, but not all of them may contain data. additionalProperties: $ref: '#/components/schemas/IonosondeStation' example: DB049: ursi: DB049 name: Dourbes fof2: "1747267201.0": 7.45 "1747267501.0": 7.50 muf: "1747267201.0": 21.66 "1747267501.0": 21.80 luf: "1747267201.0": 2.10 "1747267501.0": 2.05 band_states: "160m": Closed "80m": Short "40m": Long "20m": Long "10m": Closed EA036: ursi: EA036 name: Chilton fof2: null muf: null luf: null band_states: null IonosondeStation: type: object description: Ionosonde measurement data for a single station, covering approximately the last 24 hours. properties: ursi: type: string description: URSI code identifying the ionosonde station. example: DB049 name: type: string description: Human-readable name of the ionosonde station. example: Dourbes fof2: type: object nullable: true description: F2 layer critical frequency (foF2) measurements in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement. Can be null if there is no data. additionalProperties: type: number example: "1747267201.0": 7.45 "1747267501.0": 7.50 muf: type: object nullable: true description: Maximum Usable Frequency (MUF) for a 3000 km path in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement. Can be null if there is no data. additionalProperties: type: number example: "1747267201.0": 21.66 "1747267501.0": 21.80 luf: type: object nullable: true description: Lowest Usable Frequency (LUF, reported as fmin) in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement. Can be null if there is no data. additionalProperties: type: number example: "1747267201.0": 2.10 "1747267501.0": 2.05 band_states: type: object nullable: true description: > States of each HF amateur band, derived from the latest foF2, MUF and LUF values. Keyed by band name. Each value is one of: "Closed" (band frequency is below LUF or above MUF), "Short" (band frequency is at or above LUF and below foF2, so good for NVIS) or "Long" (band frequency is at or above foF2 and below MUF, so good for DX). Null if foF2 or MUF data is not yet available. additionalProperties: type: string enum: [ Closed, Short, Long ] example: "160m": "Closed" "80m": "Short" "40m": "Long" "20m": "Long" "10m": "Closed" SolarConditionsProviderStatus: type: object properties: name: type: string description: The name of the provider. example: HamQSL 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: number description: The last time at which this provider received data, UTC seconds since UNIX epoch. If this is zero, the provider has never updated. example: 1759579508 SpotList: type: array items: $ref: '#/components/schemas/Spot' AlertList: type: array items: $ref: '#/components/schemas/Alert' DxStats: type: object description: Spot counts keyed by DE continent additionalProperties: type: object description: Spot counts keyed by DX continent additionalProperties: type: object description: Spot counts keyed by band properties: 160m: { type: integer } 80m: { type: integer } 60m: { type: integer } 40m: { type: integer } 30m: { type: integer } 20m: { type: integer } 17m: { type: integer } 15m: { type: integer } 12m: { type: integer } 10m: { type: integer } 6m: { type: integer } ServerStatus: 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_sec": type: integer description: The amount of time the software has been running for, in seconds. example: 12345 "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 "num_alerts": type: integer description: Number of alerts 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: number description: The last time the cleanup operation ran, UTC seconds since UNIX epoch. example: 1759579508 "webserver": type: object properties: status: type: string description: The status of the web server example: OK last_page_access: type: number description: The last time a page was accessed on the web server, UTC seconds since UNIX epoch. example: 1759579508 last_api_access: type: number description: The last time an API endpoint was accessed on the web server, UTC seconds since UNIX epoch. example: 1759579508 spot_providers: type: array description: An array of all the spot providers. items: $ref: '#/components/schemas/SpotProviderStatus' alert_providers: type: array description: An array of all the alert providers. items: $ref: '#/components/schemas/AlertProviderStatus' solar_condition_providers: type: array description: An array of all the solar conditions providers. items: $ref: '#/components/schemas/SolarConditionsProviderStatus' Options: 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: $ref: '#/components/schemas/SIG' sources: type: array description: An array of all the supported data sources. 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/v1/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 spot_allowed: type: boolean description: Whether the POST /spot call, to add spots to the server directly via its API, is permitted on this server. example: true spot_submit_providers: type: object description: > A map of SIG name to a list of provider names that support upstream spot submission for that SIG. If a SIG appears as a key here, the POST /spot endpoint accepts `submit_upstream: true` for spots with that SIG, and will forward the spot to one of the listed providers. Omitted if no providers support upstream submission. additionalProperties: type: array items: type: string example: POTA: [POTA] SOTA: [SOTA] CallLookup: type: object properties: call: type: string description: Callsign, as provided to the API example: M0TRT name: type: string description: Name of the operator example: Ian qth: type: string description: QTH of the operator. This could be from any SIG refs or could be from online lookup of their home QTH. example: Dorset country: type: string description: Country of the operator. Note that this is named "country" for commonality with other amateur radio tools, but in reality this is more of a "DXCC Name", as it includes many options which are not countries, just territories that DXCC uniquely identifies. example: England flag: type: string description: Country flag of the operator. This is limited to the range of emoji flags. For some DXCCs there may not be an official emoji flag, e.g. Northern Ireland, so the appearance may vary depending on your browser and operating system. Some small islands may also have no flag. Many DXCCs may also share a flag, e.g. mainland Spain, Balearic Islands, etc. example: "" continent: description: Continent of the operator $ref: "#/components/schemas/Continent" dxcc_id: type: integer description: DXCC ID of the operator example: 235 cq_zone: type: integer description: CQ zone of the operator example: 27 itu_zone: type: integer description: ITU zone of the operator example: 14 grid: type: string description: Maidenhead grid locator for the operator's QTH. This could be from an online lookup service, or just based on the DXCC. example: IO91aa latitude: type: number description: Latitude of the operator's QTH, in degrees. This could be from an online lookup service, or just based on the DXCC. example: 51.2345 longitude: type: number description: Longitude of the opertor's QTH, in degrees. This could be from an online lookup service, or just based on the DXCC. example: -1.2345 location_source: description: Where we got the location (grid/latitude/longitude) from. Unlike a spot where we might have a summit position or WAB square, here the only options are an online QTH lookup, or a location based purely on DXCC, or nothing. $ref: "#/components/schemas/LocationSourceForAlert" GridLookup: type: object properties: center: type: object properties: latitude: type: number description: Latitude of the centre of the grid reference. example: 0.0 longitude: type: number description: Longitude of the centre of the grid reference. example: 0.0 cq_zone: type: number description: CQ zone of the centre of the grid reference. example: 1 itu_zone: type: number description: ITU zone of the centre of the grid reference. example: 1 southwest: type: object properties: latitude: type: number description: Latitude of the south-west corner of the grid square. example: 0.0 longitude: type: number description: Longitude of the south-west corner of the grid square. example: 0.0 northeast: type: object properties: latitude: type: number description: Latitude of the north-east corner of the grid square. example: 0.0 longitude: type: number description: Longitude of the north-east corner of the grid square. example: 0.0