Files
beacon-server/docs/swagger.yaml
T
Enot (ded) Skelly 31bcda03b9 add swagger
change to named functions in route handlers for swagger docs
2026-05-28 15:11:04 -07:00

1168 lines
29 KiB
YAML

basePath: /api/v1
definitions:
api.Channel:
properties:
channelHash:
description: hex-encoded single-byte hash
type: string
hashtag:
description: 'tag name without # prefix'
type: string
id:
type: integer
isHashtag:
description: true if derived from a hashtag PSK
type: boolean
keyFingerprint:
description: first 8 bytes of SHA256(key), hex-encoded
type: string
keyKnown:
description: true if Tower has a decryption key
type: boolean
lastSeen:
description: epoch ms
type: integer
messageCount:
type: integer
name:
description: display name, nil if not set
type: string
type: object
api.IATA:
properties:
displayName:
type: string
iata:
type: string
lat:
type: number
lon:
type: number
type: object
api.Node:
properties:
firstSeen:
description: epoch ms
type: integer
id:
type: string
lastAdvertAt:
description: epoch ms, nil if no advert received
type: integer
lastSeen:
description: epoch ms
type: integer
lat:
type: number
lng:
type: number
locationSource:
description: e.g. "advert", "manual"
type: string
metadata:
description: raw JSONB metadata
minFirmwareVersion:
description: derived from capability flags
type: string
name:
type: string
nodeType:
description: 1=companion, 2=repeater, 3=room server
type: integer
nodeTypeName:
type: string
publicKey:
description: hex-encoded public key
type: string
supportsMultibytePaths:
description: firmware >= 1.14.0
type: boolean
supportsMultibyteTraces:
description: firmware >= 1.11.0
type: boolean
type: object
api.ObservationPoint:
properties:
activeObservers:
type: integer
hour:
description: epoch ms, start of bucket
type: integer
iata:
type: string
observationCount:
type: integer
uniquePackets:
type: integer
type: object
api.Observer:
properties:
batteryLevel:
description: volts, nil if mains powered
type: number
brokers:
description: broker names this observer has been seen on
items:
$ref: '#/definitions/api.ObserverBroker'
type: array
displayName:
description: friendly name from /status messages
type: string
firmwareBuild:
type: string
firmwareVersion:
type: string
firstSeen:
description: epoch ms
type: integer
hardwareModel:
type: string
iata:
description: most recently heard IATA
type: string
id:
type: string
lastSeen:
description: epoch ms
type: integer
lastStatusAt:
description: epoch ms
type: integer
observationCount:
type: integer
observerType:
description: e.g. "meshcoretomqtt", "meshcoreha"
type: string
publicKey:
description: hex-encoded public key
type: string
radioBwKhz:
description: bandwidth in kHz
type: number
radioCr:
description: coding rate denominator
type: integer
radioFreqMhz:
description: MHz e.g. 910.525
type: number
radioSf:
description: LoRa spreading factor
type: integer
softwareVersion:
type: string
status:
description: '"online" or "offline" derived from last_status_at'
type: string
statusMetadata:
description: raw /status JSON payload
uptimeSeconds:
type: integer
type: object
api.ObserverBroker:
properties:
lastPacketAt:
description: epoch ms, last packet received via this broker; 0 if none
type: integer
lastSeenAt:
description: epoch ms, last time observer was seen on this broker
type: integer
name:
description: broker name e.g. "mqtt1"
type: string
type: object
api.ObserverTelemetry:
properties:
interval:
type: string
points:
items:
$ref: '#/definitions/api.ObserverTelemetryPoint'
type: array
range:
type: string
type: object
api.ObserverTelemetryPoint:
properties:
airtimeRxPct:
type: number
airtimeTxPct:
type: number
batteryMv:
type: integer
noiseFloorDb:
type: number
queueLength:
type: integer
receiveErrors:
type: integer
t:
description: epoch ms
type: integer
uptimeSeconds:
type: integer
type: object
api.Packet:
properties:
channelHash:
description: hex-encoded
type: string
decrypted:
type: boolean
firstHeardAt:
description: epoch ms
type: integer
lastHeardAt:
description: epoch ms
type: integer
observationCount:
type: integer
observations:
items:
$ref: '#/definitions/api.PacketObservationDetail'
type: array
originPubkey:
description: hex-encoded
type: string
packetHash:
description: hex-encoded
type: string
parsedPayload: {}
payloadType:
type: integer
payloadTypeName:
type: string
payloadVersion:
type: integer
rawPayload:
description: hex-encoded
type: string
routeType:
type: integer
routeTypeName:
type: string
transportCodes:
description: hex-encoded
type: string
type: object
api.PacketObservationDetail:
properties:
hashSize:
type: integer
heardAt:
description: epoch ms
type: integer
hopCount:
type: integer
iata:
type: string
id:
type: integer
observerId:
type: string
observerName:
type: string
pathBytes:
description: hex-encoded
type: string
pathLengthByte:
type: integer
propagationTimeMs:
type: integer
radio:
$ref: '#/definitions/api.PacketRadio'
resolvedPath:
items:
$ref: '#/definitions/api.ResolvedHop'
type: array
rssi:
type: integer
snr:
type: number
sourceBroker:
type: string
type: object
api.PacketRadio:
properties:
bandwidthKhz:
type: number
codingRate:
type: integer
freqMhz:
type: number
spreadFactor:
type: integer
type: object
api.PayloadBreakdownItem:
properties:
count:
type: integer
payloadType:
type: integer
payloadTypeName:
type: string
type: object
api.Region:
properties:
centerLat:
description: map center latitude
type: number
centerLng:
description: map center longitude
type: number
description:
type: string
iatas:
description: member IATA codes
items:
type: string
type: array
id:
type: integer
name:
type: string
slug:
description: URL-safe identifier e.g. "western-canada"
type: string
zoomLevel:
description: suggested map zoom level
type: integer
type: object
api.RegionSummary:
properties:
id:
type: integer
name:
type: string
slug:
description: URL-safe identifier e.g. "western-canada"
type: string
type: object
api.ResolvedHop:
properties:
confidence:
description: '"high", "low", "unknown"'
type: string
node:
$ref: '#/definitions/api.ResolvedNode'
type: object
api.ResolvedNode:
properties:
id:
type: string
latitude:
type: number
longitude:
type: number
name:
type: string
publicKey:
description: hex-encoded prefix
type: string
type: object
api.StatsOverview:
properties:
activeIatas:
type: integer
activeObservers:
type: integer
totalObservations:
type: integer
totalPackets:
type: integer
windowHours:
description: always 24 for now
type: integer
type: object
api.TopNode:
properties:
iata:
type: string
lastHeard:
description: epoch ms
type: integer
nodeId:
type: string
nodeName:
type: string
nodeType:
type: integer
nodeTypeName:
type: string
observationCount:
type: integer
type: object
api.TopObserver:
properties:
displayName:
type: string
iata:
type: string
observationCount:
type: integer
observerId:
type: string
observerType:
type: string
type: object
handlers.APIError:
properties:
code:
description: e.g. "not_found", "bad_request"
type: string
message:
description: e.g. "channel not found"
type: string
type: object
handlers.BrokerStatus:
properties:
connected:
type: boolean
name:
type: string
type: object
host: localhost:8080
info:
contact:
name: MeshCore Tower
url: https://github.com/MeshCore-Tower/tower-server
description: MeshCore network observation backend. Ingests LoRa packets from MQTT
brokers, stores in PostgreSQL, and streams live events via WebSocket.
license:
name: MIT
termsOfService: https://github.com/MeshCore-Tower/tower-server
title: MeshCore Tower API
version: "1.0"
paths:
/brokers:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/handlers.BrokerStatus'
type: array
summary: List all MQTT brokers and their connection status
tags:
- Brokers
/channels:
get:
parameters:
- description: Single-byte channel hash (hex)
in: query
name: hash
type: string
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: last_seen epoch ms of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List channels
tags:
- Channels
/channels/{channelID}:
get:
parameters:
- description: Channel integer ID
in: path
name: channelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.Channel'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get channel detail
tags:
- Channels
/channels/{channelID}/messages:
get:
parameters:
- description: Channel integer ID
in: path
name: channelID
required: true
type: integer
- description: Return messages after this epoch ms
in: query
name: since
type: integer
- description: Filter by IATA code
in: query
name: iata
type: string
- description: Message ID of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List messages for a channel
tags:
- Channels
/iatas:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/api.IATA'
type: array
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: List all IATA codes
tags:
- IATAs
/iatas/{iata}:
get:
parameters:
- description: 3-letter IATA code
in: path
name: iata
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.IATA'
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get a single IATA code
tags:
- IATAs
/messages:
get:
parameters:
- description: Filter by channel integer ID (mutually exclusive with channelHash)
in: query
name: channelID
type: integer
- description: Filter by channel hash byte hex (mutually exclusive with channelID)
in: query
name: channelHash
type: string
- description: Return messages after this epoch ms
in: query
name: since
type: integer
- description: Filter by IATA code
in: query
name: iata
type: string
- description: Message ID of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List channel messages
tags:
- Messages
/nodes:
get:
parameters:
- description: Node type integer (1=companion, 2=repeater, 3=room_server, 4=sensor)
in: query
name: type
type: integer
- description: Node type name (companion, repeater, room_server, sensor)
in: query
name: typeName
type: string
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: Partial case-insensitive name match
in: query
name: name
type: string
- description: Exact public key match (hex)
in: query
name: pubkey
type: string
- description: Filter to nodes with firmware >= 1.14.0
in: query
name: supportsMultibytePaths
type: boolean
- description: Filter to nodes with firmware >= 1.11.0
in: query
name: supportsMultibyteTraces
type: boolean
- description: last_seen epoch ms of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List nodes
tags:
- Nodes
/nodes/{nodeId}:
get:
parameters:
- description: Node UUID
in: path
name: nodeId
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.Node'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get node detail
tags:
- Nodes
/nodes/{nodeId}/observations:
get:
parameters:
- description: Node UUID
in: path
name: nodeId
required: true
type: string
- description: Observation ID of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List packet observations originating from a node
tags:
- Nodes
/observers:
get:
parameters:
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: Filter by observer type (e.g. meshcoretomqtt, meshcore-ha)
in: query
name: type
type: string
- description: Filter by broker name
in: query
name: broker
type: string
- description: Filter by status (online or offline)
in: query
name: status
type: string
- description: Partial case-insensitive display name match
in: query
name: name
type: string
- description: last_seen epoch ms of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List observers
tags:
- Observers
/observers/{observerId}:
get:
parameters:
- description: Observer UUID
in: path
name: observerId
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.Observer'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get observer detail
tags:
- Observers
/observers/{observerId}/adverts:
get:
parameters:
- description: Observer UUID
in: path
name: observerId
required: true
type: string
- description: Observation ID of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List advert packets heard by an observer
tags:
- Observers
/observers/{observerId}/telemetry:
get:
parameters:
- description: Observer UUID
in: path
name: observerId
required: true
type: string
- description: Duration window e.g. 24h, 48h, 168h (default 24h)
in: query
name: range
type: string
- description: Return points after this telemetry ID for WS reconnection backfill
in: query
name: afterId
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.ObserverTelemetry'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get observer telemetry history
tags:
- Observers
/packets:
get:
parameters:
- description: Filter by payload type integer
in: query
name: payloadType
type: integer
- description: Filter by payload type name (advert, grp_txt, txt_msg, trace,
anon_req)
in: query
name: payloadTypeName
type: string
- description: Filter by route type (0=transport_flood, 1=flood, 2=direct, 3=transport_direct)
in: query
name: routeType
type: integer
- description: Filter by latest observation IATA (case-insensitive)
in: query
name: iata
type: string
- description: Filter by first_heard_at >= since (epoch ms)
in: query
name: since
type: integer
- description: Filter by first_heard_at <= until (epoch ms)
in: query
name: until
type: integer
- description: last_heard_at epoch ms of last item for pagination
in: query
name: cursor
type: integer
- description: Max results (default 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: List packets
tags:
- Packets
/packets/{packetHash}:
get:
parameters:
- description: Packet hash (hex)
in: path
name: packetHash
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.Packet'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get full packet detail
tags:
- Packets
/regions:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/api.RegionSummary'
type: array
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: List all regions
tags:
- Regions
/regions/{regionId}:
get:
parameters:
- description: Region ID
in: path
name: regionId
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.Region'
"400":
description: Bad Request
schema:
$ref: '#/definitions/handlers.APIError'
"404":
description: Not Found
schema:
$ref: '#/definitions/handlers.APIError'
summary: Get a single region
tags:
- Regions
/stats/observations:
get:
parameters:
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: Start of window epoch ms (default 7 days ago)
in: query
name: since
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/api.ObservationPoint'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: Hourly observation time series
tags:
- Stats
/stats/overview:
get:
parameters:
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.StatsOverview'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: Network overview stats (last 24h)
tags:
- Stats
/stats/payload-breakdown:
get:
parameters:
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: Start of window epoch ms (default last 24h)
in: query
name: since
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/api.PayloadBreakdownItem'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: Observation counts by payload type (last 24h by default)
tags:
- Stats
/stats/top-nodes:
get:
parameters:
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: Max results (default 10)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/api.TopNode'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: Top N nodes by observation count (from materialized view)
tags:
- Stats
/stats/top-observers:
get:
parameters:
- description: Filter by IATA code (case-insensitive)
in: query
name: iata
type: string
- description: Start of window epoch ms (default last 24h)
in: query
name: since
type: integer
- description: Max results (default 10)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/api.TopObserver'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/handlers.APIError'
summary: Top N observers by observation count (last 24h by default)
tags:
- Stats
schemes:
- http
- https
swagger: "2.0"
tags:
- description: Airport/location codes that group observers and packets
name: IATAs
- description: Super-regions grouping multiple IATAs
name: Regions
- description: MeshCore MQTT observers (gateways)
name: Observers
- description: MeshCore radio nodes
name: Nodes
- description: LoRa packets heard by observers
name: Packets
- description: MeshCore group text channels
name: Channels
- description: Decrypted channel messages
name: Messages
- description: MQTT broker connection status
name: Brokers
- description: Network statistics and time series
name: Stats