openapi: 3.0.4
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.
  contact:
    email: ian@ianrenton.com
  license:
    name: The Unlicense
    url: https://unlicense.org/#the-unlicense
  version: v1
servers:
  - url: https://spothole.app/api/v1
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.
      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: number
        - 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: number
        - 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: number
        - 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
              - ZLOTA
              - WOTA
              - BOTA
              - Cluster
              - RBN
              - APRS-IS
              - UKPacketNet
        - 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."
          required: false
          schema:
            type: string
            enum:
              - POTA
              - SOTA
              - WWFF
              - WWBOTA
              - GMA
              - HEMA
              - WCA
              - MOTA
              - SIOTA
              - ARLHS
              - ILLW
              - ZLOTA
              - IOTA
              - WOTA
              - BOTA
              - WAB
              - WAI
        - 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 what Field Spotter uses to exclude generic cluster spots and only retrieve xOTA things."
          required: false
          schema:
            type: boolean
            default: false
        - 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."
          required: false
          schema:
            type: boolean
            default: false
        - 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
              - MFSK
              - MFSK32
              - PKT
        - 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
        - name: dedupe
          in: query
          description: "\"De-duplicate\" the spots, returning only the latest spot for any given callsign."
          required: false
          schema:
            type: boolean
            default: false
        - 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."
          required: false
          schema:
            type: string
        - name: comment_includes
          in: query
          description: "Return only spots where the comment includes the provided string (case-insensitive)."
          required: false
          schema:
            type: string
        - 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.)"
          required: false
          schema:
            type: boolean
            default: false
        - name: allow_qrt
          in: query
          description: Allow spots that are known to be QRT to be returned.
          required: false
          schema:
            type: boolean
            default: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Spot'


  /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.
      operationId: spots
      parameters:
        - name: limit
          in: query
          description: Limit the number of alerts in the response
          required: false
          schema:
            type: integer
        - 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.
          required: false
          schema:
            type: integer
        - 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.
          required: false
          schema:
            type: integer
        - 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.
          required: false
          schema:
            type: boolean
        - 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."
          required: false
          schema:
            type: string
            enum:
              - POTA
              - SOTA
              - WWFF
              - WWBOTA
              - GMA
              - HEMA
              - ParksNPeaks
              - ZLOTA
              - WOTA
              - BOTA
              - Cluster
              - RBN
              - APRS-IS
              - UKPacketNet
        - 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."
          required: false
          schema:
            type: string
            enum:
              - POTA
              - SOTA
              - WWFF
              - WWBOTA
              - GMA
              - HEMA
              - WCA
              - MOTA
              - SIOTA
              - ARLHS
              - ILLW
              - ZLOTA
              - IOTA
              - WOTA
              - BOTA
              - WAB
              - WAI
        - 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."
          required: false
          schema:
            type: string
            enum:
              - EU
              - NA
              - SA
              - AS
              - AF
              - OC
              - AN
        - 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."
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Alert'


  /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:
                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'


  /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.
      operationId: options
      responses:
        '200':
          description: Success
          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:
                      $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


  /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.
      operationId: call
      parameters:
        - name: call
          in: query
          description: A callsign
          required: true
          type: string
          example: M0TRT
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                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
                  country:
                    type: string
                    description: Country of the operator
                    example: United Kingdom
                  flag:
                    type: string
                    description: Country flag of the operator
                    example: ""
                  continent:
                    type: string
                    description: Continent of the operator
                    enum:
                      - EU
                      - NA
                      - SA
                      - AS
                      - AF
                      - OC
                      - AN
                    example: EU
                  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:
                    type: string
                    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.
                    enum:
                      - "HOME QTH"
                      - DXCC
                      - NONE
                    example: "HOME QTH"
        '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:
        - name: sig
          in: query
          description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
          required: true
          type: string
          enum:
            - POTA
            - SOTA
            - WWFF
            - WWBOTA
            - GMA
            - HEMA
            - WCA
            - MOTA
            - SIOTA
            - ARLHS
            - ILLW
            - ZLOTA
            - IOTA
            - WOTA
            - BOTA
            - WAB
            - WAI
          example: POTA
        - name: id
          in: query
          description: ID of a reference in that SIG
          required: true
          type: string
          example: GB-0001
      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"


  /spot:
    post:
      tags:
        - Spots
      summary: Add a spot
      description: "Supply a new spot object, which will be added to the system. Currently, this will not be reported up the chain to a cluster, POTA, SOTA etc. This may be introduced in a future version. cURL example: `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
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Spot'
      responses:
        '200':
          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:
  schemas:
    SIGRef:
      type: object
      properties:
        id:
          type: string
          description: SIG reference ID.
          example: GB-0001
        sig:
          type: string
          description: SIG that this reference is in.
          enum:
            - POTA
            - SOTA
            - WWFF
            - WWBOTA
            - GMA
            - HEMA
            - WCA
            - MOTA
            - SIOTA
            - ARLHS
            - ILLW
            - ZLOTA
            - IOTA
            - WOTA
            - BOTA
            - WAB
            - WAI
          example: POTA
        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

    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_country:
          type: string
          description: Country of the DX operator
          example: United Kingdom
        dx_flag:
          type: string
          description: Country flag of the DX operator
          example: ""
        dx_continent:
          type: string
          description: Continent of the DX operator
          enum:
            - EU
            - NA
            - SA
            - AS
            - AF
            - OC
            - AN
          example: EU
        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:
          type: string
          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.
          enum:
            - SPOT
            - "SIG REF LOOKUP"
            - "WAB/WAI GRID"
            - "HOME QTH"
            - DXCC
            - NONE
          example: SPOT
        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 spotter
          example: United Kingdom
        de_flag:
          type: string
          description: Country flag of the spotter
          example: ""
        de_continent:
          type: string
          enum:
            - EU
            - NA
            - SA
            - AS
            - AF
            - OC
            - AN
          description: Continent of the spotter
          example: EU
        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:
          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
            - MFSK
            - MFSK32
            - PKT
          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 Hz
          example: 7150500
        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: 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:
          type: string
          description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
          enum:
            - POTA
            - SOTA
            - WWFF
            - WWBOTA
            - GMA
            - HEMA
            - WCA
            - MOTA
            - SIOTA
            - ARLHS
            - ILLW
            - ZLOTA
            - IOTA
            - WOTA
            - BOTA
            - WAB
            - WAI
          example: POTA
        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
        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
        band_color:
          type: string
          descripton: Colour to represent this spot, if a client chooses to colour spots based on their frequency band, using PSK Reporter's default colours. HTML colour e.g. hex.
          example: #ff0000"
        band_contrast_color:
          type: string
          descripton: Black or white, whichever best contrasts with "band_color".
          example: "white"
        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
            - ZLOTA
            - WOTA
            - Cluster
            - RBN
            - APRS-IS
            - UKPacketNet
          example: POTA
        source_id:
          type: string
          description: The ID the source gave it, if any.
          example: "GUID-123456"


    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. This, and the subsequent fields, assume that all activators will be in the same country!
          example: United Kingdom
        dx_flag:
          type: string
          description: Country flag of the DX operator
          example: ""
        dx_continent:
          type: string
          description: Continent of the DX operator
          enum:
            - EU
            - NA
            - SA
            - AS
            - AF
            - OC
            - AN
          example: EU
        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:
          type: string
          description: Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
          enum:
            - POTA
            - SOTA
            - WWFF
            - WWBOTA
            - GMA
            - HEMA
            - WCA
            - MOTA
            - SIOTA
            - ARLHS
            - ILLW
            - ZLOTA
            - IOTA
            - WOTA
            - BOTA
            - WAB
            - WAI
          example: POTA
        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
        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
        source:
          type: string
          description: Where we got the alert from.
          enum:
            - POTA
            - SOTA
            - WWFF
            - WWBOTA
            - GMA
            - HEMA
            - ParksNPeaks
            - ZLOTA
            - WOTA
            - BOTA
            - Cluster
            - RBN
            - APRS-IS
            - UKPacketNet
          example: POTA
        source_id:
          type: string
          description: The ID the source gave it, if any.
          example: "GUID-123456"

    SpotProviderStatus:
      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: number
          description: The last time at which this provider received data, UTC seconds since UNIX epoch.
          example: 1759579508
        last_spot:
          type: number
          description: The time of the latest spot received by this provider, UTC seconds since UNIX epoch.
          example: 1759579508

    AlertProviderStatus:
      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: number
          description: The last time at which this provider received data, UTC seconds since UNIX epoch.
          example: 1759579508

    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 Hz.
          example: 7000000
        end_freq:
          type: int
          description: The end frequency of this band, in Hz.
          example: 7200000
        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

    SIG:
      type: object
      properties:
        name:
          type: string
          description: The abbreviated name of the SIG
          example: POTA
        description:
          type: string
          description: The full name of the SIG
          example: Parks on the Air
        icon:
          type: string
          description: 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
        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+"