Files
2026-06-09 15:50:09 -04:00

4149 lines
119 KiB
YAML

openapi: 3.0.0
info:
title: pyMC Repeater API
description: |
REST API for pyMC Repeater - LoRa mesh network repeater with room server functionality.
## Features
- System statistics and monitoring
- Packet history and analysis
- Identity management
- Access Control Lists (ACL)
- Room server messaging
- CAD calibration
- Noise floor monitoring
version: 1.0.0
contact:
name: pyMC Repeater
url: https://github.com/rightup/pyMC_Repeater
servers:
- url: /api
description: Current server (relative URLs with /api prefix)
- url: /
description: Current server root (for /auth endpoints)
- url: http://localhost:8080/api
description: Local development server
- url: http://{host}:8080/api
description: Custom host
variables:
host:
default: localhost
description: Repeater IP address or hostname
tags:
- name: Authentication
description: User authentication and API token management
- name: System
description: System statistics and control
- name: GPS
description: Local GPS receiver diagnostics
- name: Packets
description: Packet history and statistics
- name: Charts
description: Graph data and RRD metrics
- name: Noise Floor
description: Noise floor monitoring
- name: CAD Calibration
description: Channel Activity Detection calibration
- name: Adverts
description: Advertisement and contact management
- name: Transport Keys
description: Transport encryption key management
- name: Network Policy
description: Network flood policy and neighbor management
- name: Identities
description: Identity management
- name: ACL
description: Access Control Lists
- name: Room Server
description: Room server messaging
paths:
# ============================================================================
# Authentication Endpoints
# ============================================================================
/auth/login:
post:
tags: [Authentication]
summary: User login
description: Authenticate with username/password and receive JWT token
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [username, password, client_id]
properties:
username:
type: string
example: admin
password:
type: string
format: password
example: admin123
client_id:
type: string
description: Unique client identifier
example: web-client-abc123
responses:
'200':
description: Login successful
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
description: JWT token
expires_in:
type: integer
description: Token expiry in seconds
username:
type: string
'401':
description: Invalid credentials
/auth/refresh:
post:
tags: [Authentication]
summary: Refresh JWT token
description: Extend session by refreshing JWT token
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [client_id]
properties:
client_id:
type: string
responses:
'200':
description: Token refreshed
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
expires_in:
type: integer
username:
type: string
/auth/verify:
get:
tags: [Authentication]
summary: Verify authentication
description: Check if current authentication is valid
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: Authentication valid
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
authenticated:
type: boolean
user:
type: object
/auth/change_password:
post:
tags: [Authentication]
summary: Change admin password
description: Change the admin password (requires authentication)
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [current_password, new_password]
properties:
current_password:
type: string
format: password
new_password:
type: string
format: password
minLength: 8
responses:
'200':
description: Password changed successfully
'401':
description: Current password incorrect
'400':
description: Invalid password format
/auth/tokens:
get:
tags: [Authentication]
summary: List API tokens
description: Get list of all API tokens (RESTful endpoint)
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: List of tokens
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
tokens:
type: array
items:
type: object
properties:
id:
type: integer
name:
type: string
created_at:
type: string
format: date-time
last_used:
type: string
format: date-time
post:
tags: [Authentication]
summary: Create API token
description: Generate a new API token (RESTful endpoint)
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
description: Friendly name for the token
example: "My API Token"
responses:
'200':
description: Token created
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
description: The plaintext token (only shown once)
token_id:
type: integer
name:
type: string
warning:
type: string
/auth/tokens/{token_id}:
delete:
tags: [Authentication]
summary: Revoke API token
description: Delete/revoke an API token by ID (RESTful endpoint)
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: token_id
in: path
required: true
schema:
type: integer
responses:
'200':
description: Token revoked
'404':
description: Token not found
# ============================================================================
# System Endpoints
# ============================================================================
/stats:
get:
tags: [System]
summary: Get system statistics
description: Returns repeater uptime, packet counts, and version information
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
uptime_secs:
type: integer
example: 3600
packets_received:
type: integer
example: 150
packets_sent:
type: integer
example: 120
version:
type: string
example: "1.0.0"
core_version:
type: string
example: "0.5.0"
/gps:
get:
tags: [GPS]
summary: Get local GPS diagnostics
description: Returns parsed NMEA fix, position, motion, accuracy, satellites, and raw sentence health.
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: GPS diagnostics snapshot
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
enabled:
type: boolean
running:
type: boolean
status:
type: object
fix:
type: object
position:
type: object
description: Effective receiver position for API clients
gps_position:
type: object
description: Raw position reported by the GPS receiver, even before a valid fix
manual_position:
type: object
nullable: true
description: Configured repeater latitude/longitude, when set to a non-zero coordinate
position_meta:
type: object
properties:
source:
type: string
enum: [gps, manual_config]
source_label:
type: string
policy:
type: string
enum: [manual_until_gps_fix, gps_only]
manual_config_available:
type: boolean
gps_fix_valid:
type: boolean
motion:
type: object
accuracy:
type: object
time:
type: object
time_sync:
type: object
description: GPS-to-system-clock sync status
properties:
enabled:
type: boolean
state:
type: string
enum: [disabled, waiting_for_fix, waiting_for_time, ready, in_sync, synced, error, ignored]
last_attempt:
type: string
nullable: true
last_success:
type: string
nullable: true
last_error:
type: string
nullable: true
last_gps_time:
type: string
nullable: true
last_offset_seconds:
type: number
nullable: true
location_update:
type: object
description: GPS-fix-to-repeater-location update status
properties:
enabled:
type: boolean
state:
type: string
enum: [disabled, unconfigured, waiting_for_fix, waiting_for_position, ready, updated, skipped, error]
last_attempt:
type: string
nullable: true
last_success:
type: string
nullable: true
last_error:
type: string
nullable: true
last_latitude:
type: number
nullable: true
last_longitude:
type: number
nullable: true
satellites:
type: object
nmea:
type: object
raw_attributes:
type: object
additionalProperties: true
/gps_stream:
get:
tags: [GPS]
summary: GPS diagnostics SSE stream
description: Server-Sent Events stream of live GPS diagnostics snapshots.
responses:
'200':
description: SSE stream
content:
text/event-stream:
schema:
type: string
/send_advert:
post:
tags: [System]
summary: Send repeater advertisement
description: Manually trigger sending a repeater advertisement packet
responses:
'200':
description: Advertisement sent
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'405':
description: Method not allowed
/logs:
get:
tags: [System]
summary: Get system logs
description: Retrieve recent system logs
responses:
'200':
description: Log entries
content:
application/json:
schema:
type: object
required: [logs]
properties:
logs:
type: array
items:
type: object
required: [message, timestamp, level]
properties:
message:
type: string
timestamp:
type: string
format: date-time
level:
type: string
error:
type: string
/logs_stream:
get:
tags: [System]
summary: Stream system logs
description: Server-Sent Events stream of live system log entries.
parameters:
- name: since_id
in: query
required: false
schema:
type: integer
description: Resume the stream after this log entry id.
responses:
'200':
description: SSE stream
content:
text/event-stream:
schema:
type: string
/hardware_stats:
get:
tags: [System]
summary: Get hardware statistics
description: CPU, memory, disk usage statistics
responses:
'200':
description: Hardware stats
content:
application/json:
schema:
type: object
properties:
cpu_percent:
type: number
memory_percent:
type: number
disk_usage:
type: object
/hardware_processes:
get:
tags: [System]
summary: Get process information
description: List running processes and their resource usage
responses:
'200':
description: Process list
content:
application/json:
schema:
type: array
items:
type: object
/restart_service:
post:
tags: [System]
summary: Restart repeater service
description: Restart the repeater daemon service
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: Service restart initiated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/validate_config:
get:
tags: [System]
summary: Validate config.yaml before restart
description: Checks config syntax and required settings for the selected radio type.
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: Validation completed
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
valid:
type: boolean
blocked_restart:
type: boolean
errors:
type: array
items:
type: object
properties:
path:
type: string
message:
type: string
warnings:
type: array
items:
type: object
properties:
path:
type: string
message:
type: string
summary:
type: object
properties:
error_count:
type: integer
warning_count:
type: integer
config_path:
type: string
message:
type: string
/openapi:
get:
tags: [System]
summary: Get OpenAPI specification
description: Returns the OpenAPI/Swagger specification for this API
responses:
'200':
description: OpenAPI spec
content:
application/json:
schema:
type: object
/set_mode:
post:
tags: [System]
summary: Set repeater mode
description: |
Set TX mode. forward = repeat on; monitor = no repeat but companions/tenants can send;
no_tx = all transmission disabled (receive-only).
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [mode]
properties:
mode:
type: string
enum: [forward, monitor, no_tx]
description: |
- forward: Repeat received packets; allow all local TX (default)
- monitor: Do not repeat; allow local TX (companions, adverts, etc.)
- no_tx: Do not repeat; no local TX (receive-only)
example: forward
examples:
forward:
value:
mode: forward
monitor:
value:
mode: monitor
no_tx:
value:
mode: no_tx
responses:
'200':
description: Mode changed
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
examples:
success:
value:
success: true
data: "Mode set to forward"
'400':
description: Invalid mode
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/packet_stats:
get:
tags: [Packets]
summary: Get packet statistics
description: Returns packet counts, types, and routing statistics
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
minimum: 1
maximum: 168
description: Time range in hours (1-168 = 1 hour to 1 week)
example: 24
responses:
'200':
description: Packet statistics
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
total_packets:
type: integer
received:
type: integer
transmitted:
type: integer
dropped:
type: integer
by_type:
type: object
by_route:
type: object
/set_duty_cycle:
post:
tags: [System]
summary: Set duty cycle
description: Enable or disable duty cycle limiting
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [enabled]
properties:
enabled:
type: boolean
description: Enable duty cycle limiting
example: true
examples:
enable:
value:
enabled: true
disable:
value:
enabled: false
responses:
'200':
description: Duty cycle setting updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/update_duty_cycle_config:
post:
tags: [System]
summary: Update duty cycle configuration
description: Update detailed duty cycle timing configuration
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
enabled:
type: boolean
on_time:
type: integer
description: ON time in seconds
off_time:
type: integer
description: OFF time in seconds
example:
enabled: true
on_time: 300
off_time: 60
responses:
'200':
description: Duty cycle config updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/update_radio_config:
post:
tags: [System]
summary: Update radio configuration
description: Update LoRa radio parameters
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Radio config updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
# ============================================================================
# Packet Endpoints
# ============================================================================
/recent_packets:
get:
tags: [Packets]
summary: Get recent packets
description: Retrieve recent packet history
parameters:
- name: limit
in: query
schema:
type: integer
default: 100
minimum: 1
maximum: 1000
description: Maximum number of packets to return
responses:
'200':
description: Recent packets
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: array
items:
type: object
/packet_by_hash:
get:
tags: [Packets]
summary: Get packet by hash
parameters:
- name: packet_hash
in: query
required: true
schema:
type: string
description: Packet hash to lookup
responses:
'200':
description: Packet details
/packet_type_stats:
get:
tags: [Packets]
summary: Get packet type statistics
description: Statistics broken down by packet type
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
responses:
'200':
description: Packet type stats
content:
application/json:
schema:
type: object
/route_stats:
get:
tags: [Packets]
summary: Get route statistics
description: Statistics broken down by route type
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
responses:
'200':
description: Route stats
content:
application/json:
schema:
type: object
/filtered_packets:
get:
tags: [Packets]
summary: Get filtered packets
description: Retrieve packets filtered by type, route, and timestamp
parameters:
- name: type
in: query
schema:
type: integer
minimum: 0
maximum: 15
description: Packet type filter
- name: route
in: query
schema:
type: integer
minimum: 1
maximum: 3
description: Route type filter
- name: start_timestamp
in: query
schema:
type: integer
description: Start timestamp (Unix)
- name: end_timestamp
in: query
schema:
type: integer
description: End timestamp (Unix)
- name: limit
in: query
schema:
type: integer
default: 1000
description: Maximum results
responses:
'200':
description: Filtered packets
content:
application/json:
schema:
type: object
# ============================================================================
# Charts & RRD Endpoints
# ============================================================================
/rrd_data:
get:
tags: [Charts]
summary: Get RRD time-series data
description: |
Retrieve Round-Robin Database metrics for graphing.
**Note:** This endpoint extracts parameters from the request internally.
Parameters are handled automatically by the backend.
responses:
'200':
description: RRD time-series data
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
start_time:
type: integer
end_time:
type: integer
step:
type: integer
timestamps:
type: array
items:
type: integer
metrics:
type: object
/packet_type_graph_data:
get:
tags: [Charts]
summary: Get packet type distribution graph data
description: Returns bar chart data showing packet counts by type
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
- name: resolution
in: query
schema:
type: string
enum: [average, max, min]
default: average
- name: types
in: query
schema:
type: string
default: all
description: Comma-separated packet types or 'all'
responses:
'200':
description: Packet type graph data
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
start_time:
type: integer
end_time:
type: integer
step:
type: integer
chart_type:
type: string
example: bar
series:
type: array
items:
type: object
properties:
name:
type: string
type:
type: string
data:
type: array
items:
type: number
/metrics_graph_data:
get:
tags: [Charts]
summary: Get system metrics graph data
description: |
Returns time-series data for system metrics like packet counts, RSSI, SNR, etc.
Available metrics:
- rx_count: Received packets
- tx_count: Transmitted packets
- drop_count: Dropped packets
- avg_rssi: Average RSSI (dBm)
- avg_snr: Average SNR (dB)
- avg_length: Average packet length
- avg_score: Average score
- neighbor_count: Neighbor count
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
- name: resolution
in: query
schema:
type: string
enum: [average, max, min]
default: average
- name: metrics
in: query
schema:
type: string
default: all
description: Comma-separated metric names or 'all'
example: "rx_count,tx_count,avg_rssi"
responses:
'200':
description: Metrics graph data
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
start_time:
type: integer
end_time:
type: integer
step:
type: integer
timestamps:
type: array
items:
type: integer
series:
type: array
items:
type: object
properties:
name:
type: string
type:
type: string
data:
type: array
items:
type: number
/noise_floor_history:
get:
tags: [Noise Floor]
summary: Get noise floor history
description: Retrieve historical noise floor measurements
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
minimum: 1
maximum: 168
description: Time range in hours
responses:
'200':
description: Noise floor history
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: array
items:
type: object
/noise_floor_stats:
get:
tags: [Noise Floor]
summary: Get noise floor statistics
description: Statistical analysis of noise floor measurements
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
responses:
'200':
description: Noise floor statistics
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
min:
type: number
max:
type: number
avg:
type: number
current:
type: number
/noise_floor_chart_data:
get:
tags: [Noise Floor]
summary: Get noise floor chart data
description: Formatted noise floor data for charting
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
responses:
'200':
description: Chart-ready noise floor data
content:
application/json:
schema:
type: object
# ============================================================================
# CAD Calibration Endpoints
# ============================================================================
/cad_calibration_start:
post:
tags: [CAD Calibration]
summary: Start CAD calibration
description: Begin Channel Activity Detection calibration process
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
samples:
type: integer
default: 8
minimum: 1
maximum: 64
description: Number of samples to collect
example: 8
delay:
type: integer
default: 100
minimum: 10
maximum: 1000
description: Delay between samples in milliseconds
example: 100
examples:
default:
value:
samples: 8
delay: 100
detailed:
value:
samples: 16
delay: 50
responses:
'200':
description: Calibration started
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/cad_calibration_stop:
post:
tags: [CAD Calibration]
summary: Stop CAD calibration
responses:
'200':
description: Calibration stopped
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/save_cad_settings:
post:
tags: [CAD Calibration]
summary: Save CAD settings
description: Save calibrated CAD peak and min values to configuration
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [peak, min_val]
properties:
peak:
type: integer
minimum: 0
maximum: 255
description: CAD peak value
example: 127
min_val:
type: integer
minimum: 0
maximum: 255
description: CAD minimum value
example: 64
responses:
'200':
description: Settings saved
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/cad_calibration_stream:
get:
tags: [CAD Calibration]
summary: CAD calibration SSE stream
description: Server-Sent Events stream of calibration progress
responses:
'200':
description: SSE stream
content:
text/event-stream:
schema:
type: string
# ============================================================================
# Adverts & Contacts
# ============================================================================
/adverts_by_contact_type:
get:
tags: [Adverts]
summary: Get adverts by contact type
description: Retrieve advertisements filtered by contact type
parameters:
- name: contact_type
in: query
schema:
type: integer
description: Contact type to filter by
- name: limit
in: query
schema:
type: integer
default: 100
description: Maximum number of results
- name: hours
in: query
schema:
type: integer
default: 24
description: Time range in hours
responses:
'200':
description: Filtered adverts
content:
application/json:
schema:
type: object
/advert:
delete:
tags: [Adverts]
summary: Delete specific advert
description: Delete a specific advertisement by ID
parameters:
- name: advert_id
in: query
required: true
schema:
type: integer
description: Advert ID to delete
responses:
'200':
description: Advert deleted
content:
application/json:
schema:
type: object
# ============================================================================
# Transport Keys
# ============================================================================
/transport_keys:
get:
tags: [Transport Keys]
summary: List transport keys
description: Get list of all transport encryption keys
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: List of transport keys
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: array
items:
type: object
post:
tags: [Transport Keys]
summary: Create transport key
description: Generate a new transport encryption key
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Key name/identifier
responses:
'200':
description: Key created
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/transport_key:
get:
tags: [Transport Keys]
summary: Get transport key
description: Retrieve specific transport key details
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: key_id
in: query
required: true
schema:
type: string
description: Key ID to retrieve
responses:
'200':
description: Key details
content:
application/json:
schema:
type: object
put:
tags: [Transport Keys]
summary: Update transport key
description: Update an existing transport encryption key
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: key_id
in: query
required: true
schema:
type: string
description: Key ID to update
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Updated key name
flood_policy:
type: string
enum: [allow, deny]
description: Updated flood policy
transport_key:
type: string
description: Updated transport key hex
parent_id:
type: integer
nullable: true
description: Updated parent transport key ID
last_used:
type: string
format: date-time
description: Updated last-used timestamp in ISO-8601 format
responses:
'200':
description: Key updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
delete:
tags: [Transport Keys]
summary: Delete transport key
description: Remove a transport encryption key
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: key_id
in: query
required: true
schema:
type: string
description: Key ID to delete
responses:
'200':
description: Key deleted
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
# ============================================================================
# Network Policy
# ============================================================================
/unscoped_flood_policy:
post:
tags: [Network Policy]
summary: Update unscoped flood policy
description: Modify network flood policy settings
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Policy updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/ping_neighbor:
post:
tags: [Network Policy]
summary: Ping neighbor node
description: Send ping to a specific neighbor node
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [target_id]
properties:
target_id:
type: string
description: Target node identifier
timeout:
type: integer
description: Ping timeout in seconds
default: 10
responses:
'200':
description: Ping sent
content:
application/json:
schema:
type: object
required: [success, data]
properties:
success:
type: boolean
data:
type: object
required: [target_id, rtt_ms, snr_db, rssi, path, tag]
properties:
target_id:
type: string
rtt_ms:
type: number
snr_db:
type: number
rssi:
type: number
path:
type: array
items:
type: string
tag:
type: integer
path_hash_mode:
type: integer
message:
type: string
error:
type: string
/policy:
get:
tags: [Network Policy]
summary: Get policy document
description: Returns normalized policy engine configuration and grouped channel hash/pubkey entries.
security:
- BearerAuth: []
- ApiKeyAuth: []
responses:
'200':
description: Policy document
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
policy_file:
type: string
exists:
type: boolean
policy_engine:
type: object
groups:
type: object
post:
tags: [Network Policy]
summary: Update policy document
description: Update policy_engine configuration while preserving or replacing named groups.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
description: Accepts either root-level policy_engine fields or a nested policy_engine object.
responses:
'200':
description: Policy updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/policy_validate:
post:
tags: [Network Policy]
summary: Validate policy payload
description: Validate a policy payload without saving it to disk.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Validation result
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
valid:
type: boolean
normalized:
type: object
effective:
type: object
/policy_groups:
get:
tags: [Network Policy]
summary: List policy groups
description: List named channel hash and pubkey groups.
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: kind
in: query
required: false
schema:
type: string
enum: [channel_hashes, pubkeys]
description: Optional group kind filter.
responses:
'200':
description: Policy groups
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
post:
tags: [Network Policy]
summary: Create policy group
description: Create a named group for channel hashes or pubkeys.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [kind]
properties:
kind:
type: string
enum: [channel_hashes, pubkeys]
group_id:
type: string
friendly_name:
type: string
description:
type: string
responses:
'200':
description: Group created
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
delete:
tags: [Network Policy]
summary: Delete policy group
description: Delete a named group and all of its entries.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [kind, group_id]
properties:
kind:
type: string
enum: [channel_hashes, pubkeys]
group_id:
type: string
responses:
'200':
description: Group deleted
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/policy_group_entries:
get:
tags: [Network Policy]
summary: List group entries
description: Return entries for a specific named channel hash/pubkey group.
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: kind
in: query
required: true
schema:
type: string
enum: [channel_hashes, pubkeys]
- name: group_id
in: query
required: true
schema:
type: string
responses:
'200':
description: Group entries
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
post:
tags: [Network Policy]
summary: Add group entry
description: Add a friendly-named entry to a policy group.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [kind, group_id, value]
properties:
kind:
type: string
enum: [channel_hashes, pubkeys]
group_id:
type: string
value:
type: string
entry_id:
type: string
friendly_name:
type: string
responses:
'200':
description: Entry added
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
delete:
tags: [Network Policy]
summary: Remove group entry
description: Remove an entry by entry_id or value from a policy group.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [kind, group_id]
properties:
kind:
type: string
enum: [channel_hashes, pubkeys]
group_id:
type: string
entry_id:
type: string
value:
type: string
responses:
'200':
description: Entry removed
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
# ============================================================================
# Identity Management
# ============================================================================
/create_identity:
post:
tags: [Identities]
summary: Create new identity
description: |
Create a new companion or room server identity.
`name` must be non-empty after trimming leading/trailing whitespace (whitespace-only values are rejected).
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, type]
properties:
name:
type: string
minLength: 1
maxLength: 64
pattern: '^[a-zA-Z0-9_\-\s]+$'
description: |
Identity registration name (alphanumeric, spaces, hyphens, underscores).
Trimmed; must not be empty or whitespace-only.
example: "General Chat"
identity_key:
type: string
pattern: '^(?:[0-9a-fA-F]{64}|[0-9a-fA-F]{128})$'
description: 32- or 64-byte hex key (64 or 128 chars). Omit for auto-generation
example: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
type:
type: string
enum: [companion, room_server]
description: |
- companion: Companion identity with a TCP endpoint
- room_server: Room server for group chat
example: room_server
settings:
type: object
description: Type-specific settings
properties:
admin_password:
type: string
minLength: 4
description: Admin authentication password (room_server only)
example: "admin123"
guest_password:
type: string
minLength: 4
description: Guest authentication password (room_server only)
example: "guest123"
max_posts:
type: integer
minimum: 1
maximum: 32
default: 32
description: Maximum messages to keep (hard limit 32)
example: 32
node_name:
type: string
description: Advertised node name (companion only; defaults to identity name)
example: "My Companion"
tcp_port:
type: integer
minimum: 1
maximum: 65535
default: 5000
description: TCP listener port (companion only)
example: 5000
bind_address:
type: string
default: "0.0.0.0"
description: TCP listener bind address (companion only)
example: "0.0.0.0"
examples:
room_server:
value:
name: "General Chat"
type: room_server
settings:
admin_password: "admin123"
guest_password: "guest123"
max_posts: 32
companion:
value:
name: "My Companion"
type: companion
identity_key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
settings:
node_name: "My Companion"
tcp_port: 5000
bind_address: "0.0.0.0"
responses:
'200':
description: Identity created
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
name:
type: string
type:
type: string
hash:
type: string
public_key:
type: string
examples:
success:
value:
success: true
data:
name: "General Chat"
type: room_server
hash: "0x42"
public_key: "abc123..."
'400':
description: Invalid parameters
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/identities:
get:
tags: [Identities]
summary: List all identities
description: |
Returns configured room servers and companions plus runtime registration info.
Companion entries with missing or blank registration names are assigned a stable
`companion_<pubkeyPrefix>` name derived from the identity key and persisted when possible.
responses:
'200':
description: List of identities
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
identities:
type: array
items:
$ref: '#/components/schemas/Identity'
/identity:
get:
tags: [Identities]
summary: Get specific identity
description: Retrieve details of a specific identity by name
parameters:
- name: name
in: query
required: true
schema:
type: string
description: Identity name to retrieve
responses:
'200':
description: Identity details
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
$ref: '#/components/schemas/Identity'
/update_identity:
put:
tags: [Identities]
summary: Update identity
description: |
Modify an existing identity's configuration.
For `room_server`, `name` is required to locate the identity.
For `companion`, provide `name` OR `lookup_identity_key` OR `public_key_prefix`
(at least 8 hex characters for prefix lookups) when the registration name is unknown.
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
type:
type: string
enum: [room_server, companion]
default: room_server
name:
type: string
description: Current identity registration name (required for room_server; optional for companion if lookup fields are set)
lookup_identity_key:
type: string
description: |
Companion only: hex private identity key (full or unique prefix, min 8 hex chars)
to locate the companion when `name` is omitted.
public_key_prefix:
type: string
description: |
Companion only: ed25519 public key hex prefix (min 8 hex chars) to locate the companion when `name` is omitted.
new_name:
type: string
description: New identity name (optional; must be non-empty if provided)
identity_key:
type: string
description: New identity key (optional)
settings:
type: object
description: Updated settings
responses:
'200':
description: Identity updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/delete_identity:
delete:
tags: [Identities]
summary: Delete identity
description: |
Remove an identity from the system.
For `room_server`, `name` is required.
For `companion`, provide `name` OR `lookup_identity_key` OR `public_key_prefix`
(at least 8 hex characters for prefix lookups).
security:
- BearerAuth: []
- ApiKeyAuth: []
parameters:
- name: name
in: query
required: false
schema:
type: string
description: Identity registration name to delete (required for room_server)
- name: type
in: query
required: false
schema:
type: string
enum: [room_server, companion]
description: Identity kind (default room_server)
- name: lookup_identity_key
in: query
required: false
schema:
type: string
description: |
Companion only: hex identity key (full or unique prefix, min 8 hex chars) when `name` is omitted.
- name: public_key_prefix
in: query
required: false
schema:
type: string
description: |
Companion only: public key hex prefix (min 8 hex chars) when `name` is omitted.
responses:
'200':
description: Identity deleted
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/send_room_server_advert:
post:
tags: [Identities]
summary: Send room server advertisement
description: Broadcast a room server advertisement packet
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
description: Room server identity name
node_name:
type: string
description: Node name for the advertisement
latitude:
type: number
format: float
description: GPS latitude
example: 0.0
longitude:
type: number
format: float
description: GPS longitude
example: 0.0
disable_fwd:
type: boolean
description: Disable forwarding flag
default: false
responses:
'200':
description: Advertisement sent
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
# ============================================================================
# ACL (Access Control List)
# ============================================================================
/acl_info:
get:
tags: [ACL]
summary: Get ACL information for all identities
description: |
Get ACL configuration and statistics for all registered identities.
Returns information including:
- Identity name, type, and hash
- Max clients allowed
- Number of authenticated clients
- Password configuration status
- Read-only access setting
responses:
'200':
description: ACL information for all identities
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
acls:
type: array
items:
type: object
properties:
name:
type: string
example: "repeater"
type:
type: string
enum: [repeater, room_server]
example: "repeater"
hash:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
example: "0x42"
max_clients:
type: integer
example: 100
authenticated_clients:
type: integer
example: 5
has_admin_password:
type: boolean
example: true
has_guest_password:
type: boolean
example: true
allow_read_only:
type: boolean
example: true
total_identities:
type: integer
example: 3
total_authenticated_clients:
type: integer
example: 15
/acl_clients:
get:
tags: [ACL]
summary: List ACL clients
description: Get list of authenticated clients in access control list for an identity
parameters:
- name: identity_hash
in: query
schema:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Identity hash
example: "0x42"
- name: identity_name
in: query
schema:
type: string
description: Identity name
example: "General"
responses:
'200':
description: ACL clients list
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
clients:
type: array
items:
$ref: '#/components/schemas/ACLClient'
count:
type: integer
description: Number of clients returned
filter:
type: string
nullable: true
description: Filter applied (if any)
examples:
success:
value:
success: true
data:
clients:
- public_key: "03ccf3bb0bed9a51...21416fff"
public_key_full: "03ccf3bb0bed9a5109868a1e33ed020519aab6dbb30e42df3b11a21d21416fff"
address: "e1"
permissions: "admin"
last_activity: 1766065148
last_login_success: 1766065146
last_timestamp: 1766065146
identity_name: "rrrrr"
identity_type: "room_server"
identity_hash: "0xC5"
count: 1
filter: null
/acl_remove_client:
post:
tags: [ACL]
summary: Remove client from ACL
description: Remove a client from the access control list
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [identity_hash, client_pubkey]
properties:
identity_hash:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Identity hash
example: "0x42"
identity_name:
type: string
description: Identity name (alternative to hash)
example: "General"
client_pubkey:
type: string
pattern: '^[0-9a-fA-F]{64}$'
description: Client public key to remove
example: "abc123def456..."
responses:
'200':
description: Client removed from ACL
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/acl_stats:
get:
tags: [ACL]
summary: Get ACL statistics
description: Get statistics about access control lists
responses:
'200':
description: ACL statistics
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
total_entries:
type: integer
by_identity:
type: object
/room_messages:
get:
tags: [Room Server]
summary: Get room messages
description: |
Retrieve messages from a room with pagination.
**Max Messages Per Room**: 32 (hard limit)
- Older messages auto-deleted every 10 minutes
- Cannot be increased beyond 32
parameters:
- name: room_name
in: query
schema:
type: string
description: Name of the room (use this OR room_hash)
example: General
- name: room_hash
in: query
schema:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Hash of room identity (use this OR room_name)
example: "0x42"
- name: limit
in: query
schema:
type: integer
default: 50
minimum: 1
maximum: 100
description: Max messages to return
example: 50
- name: offset
in: query
schema:
type: integer
default: 0
minimum: 0
description: Skip first N messages (for pagination)
example: 0
- name: since_timestamp
in: query
schema:
type: number
format: float
description: Only return messages after this Unix timestamp
example: 1734567890.5
responses:
'200':
description: Messages retrieved
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
room_name:
type: string
room_hash:
type: string
messages:
type: array
items:
$ref: '#/components/schemas/RoomMessage'
count:
type: integer
description: Number of messages in this response
total:
type: integer
description: Total messages in room (max 32)
limit:
type: integer
offset:
type: integer
examples:
success:
value:
success: true
data:
room_name: "General"
room_hash: "0x42"
messages:
- id: 123
author_pubkey: "abc123def456..."
author_prefix: "abc123de"
post_timestamp: 1734567890.5
sender_timestamp: 1734567890
message_text: "Hello world"
txt_type: 0
created_at: 1734567890.5
count: 1
total: 15
limit: 50
offset: 0
'404':
description: Room not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/room_post_message:
post:
tags: [Room Server]
summary: Post message to room
description: |
Add a new message to a room server. Message will be distributed to all synced clients.
**Special author values:**
- `"server"` or `"system"` - System message, goes to ALL clients (API only)
- Any hex string - Normal message, NOT sent to that client
**Security:**
- Radio messages cannot use server key (blocked)
- API messages can use server key (for announcements)
**Rate Limits:**
- 10 messages/minute per author_pubkey
- 160 bytes max message length
- Global 1.1s gap between transmissions
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [message, author_pubkey]
properties:
room_name:
type: string
description: Name of the room (use this OR room_hash)
example: General
room_hash:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Hash of room identity (use this OR room_name)
example: "0x42"
message:
type: string
minLength: 1
maxLength: 160
description: Message text (auto-truncated at 160 bytes)
example: "Hello from API"
author_pubkey:
type: string
description: |
Author's public key as hex string (64 chars), or special values:
- "server" = system message (all clients receive)
- "system" = alias for "server"
- hex string = normal message (author won't receive)
example: "abc123def456..."
txt_type:
type: integer
default: 0
enum: [0, 2]
description: |
Message type:
- 0: Plain text
- 2: Signed plain text
example: 0
examples:
normal_message:
summary: Normal message
value:
room_name: "General"
message: "Hello everyone!"
author_pubkey: "abc123def456..."
txt_type: 0
server_message:
summary: Server announcement
value:
room_name: "General"
message: "[SERVER] Maintenance in 10 minutes"
author_pubkey: "server"
by_hash:
summary: Post by room hash
value:
room_hash: "0x42"
message: "Using hash instead of name"
author_pubkey: "abc123..."
responses:
'200':
description: Message posted
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
message_id:
type: integer
description: Database ID of created message
room_name:
type: string
room_hash:
type: string
queued_for_distribution:
type: boolean
description: Always true - distribution is async
is_server_message:
type: boolean
description: True if author_pubkey was "server"
author_filter_note:
type: string
description: Explains message distribution behavior
examples:
normal:
value:
success: true
data:
message_id: 124
room_name: "General"
room_hash: "0x42"
queued_for_distribution: true
is_server_message: false
author_filter_note: "Message will NOT be sent to author"
server:
value:
success: true
data:
message_id: 125
room_name: "General"
room_hash: "0x42"
queued_for_distribution: true
is_server_message: true
author_filter_note: "Server messages go to ALL clients"
'400':
description: Invalid parameters or rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
rate_limit:
value:
success: false
error: "Failed to add message (rate limit or validation error)"
missing_field:
value:
success: false
error: "message is required"
/room_stats:
get:
tags: [Room Server]
summary: Get room statistics
description: |
Get detailed statistics for one or all room servers.
**Room Limits:**
- 32 messages maximum per room (hard limit)
- Messages auto-expire every 10 minutes
- Author filtering: messages not sent back to author
parameters:
- name: room_name
in: query
schema:
type: string
description: Get stats for specific room (omit for all rooms)
example: General
- name: room_hash
in: query
schema:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Get stats by room hash (use this OR room_name)
example: "0x42"
responses:
'200':
description: Room statistics
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
room_name:
type: string
room_hash:
type: string
total_messages:
type: integer
minimum: 0
maximum: 32
description: Current message count (max 32)
example: 15
total_clients:
type: integer
minimum: 0
description: Total clients that have synced
example: 8
active_clients:
type: integer
minimum: 0
description: Clients active within timeout window
example: 3
max_posts:
type: integer
minimum: 1
maximum: 32
description: Message limit setting (always 32)
example: 32
sync_running:
type: boolean
description: Distribution task is active
example: true
clients:
type: array
description: List of all clients with sync status
items:
$ref: '#/components/schemas/RoomClient'
examples:
single_room:
value:
success: true
data:
room_name: "General"
room_hash: "0x42"
total_messages: 15
total_clients: 8
active_clients: 3
max_posts: 32
sync_running: true
clients:
- pubkey: "abc123..."
pubkey_prefix: "abc123de"
sync_since: 1734567890.5
unsynced_count: 5
is_active: true
all_rooms:
value:
success: true
data:
rooms:
- room_name: "General"
total_messages: 15
active_clients: 3
- room_name: "Tech"
total_messages: 8
active_clients: 1
'404':
description: Room not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/room_clients:
get:
tags: [Room Server]
summary: Get room clients
description: |
List all clients synced to a room with their status.
**Client Filtering:**
- Clients only receive messages where author_pubkey ≠ client_pubkey
- unsynced_count shows pending messages for each client
- is_active indicates client synced within timeout window
parameters:
- name: room_name
in: query
schema:
type: string
description: Room name
example: General
- name: room_hash
in: query
schema:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Room hash (use this OR room_name)
example: "0x42"
responses:
'200':
description: Client list
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
room_name:
type: string
room_hash:
type: string
clients:
type: array
items:
$ref: '#/components/schemas/RoomClient'
examples:
success:
value:
success: true
data:
room_name: "General"
room_hash: "0x42"
clients:
- pubkey: "abc123def456..."
pubkey_prefix: "abc123de"
sync_since: 1734567890.5
unsynced_count: 5
pending_ack: false
push_failures: 0
last_activity: 1734567890.5
in_acl: true
is_active: true
'404':
description: Room not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/room_message:
delete:
tags: [Room Server]
summary: Delete specific message
parameters:
- name: room_name
in: query
schema:
type: string
- name: room_hash
in: query
schema:
type: string
- name: message_id
in: query
required: true
schema:
type: integer
responses:
'200':
description: Message deleted
/room_messages_clear:
delete:
tags: [Room Server]
summary: Clear all room messages
description: ⚠️ Destructive operation - cannot be undone!
parameters:
- name: room_name
in: query
schema:
type: string
- name: room_hash
in: query
schema:
type: string
responses:
'200':
description: Messages cleared
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
deleted_count:
type: integer
/needs_setup:
get:
tags: [System]
summary: Check setup wizard status
responses:
'200':
description: Setup status
content:
application/json:
schema:
type: object
/site_info:
get:
tags: [System]
summary: Get site and host info
responses:
'200':
description: Site info
content:
application/json:
schema:
type: object
/hardware_options:
get:
tags: [System]
summary: Get supported hardware options
responses:
'200':
description: Hardware options
content:
application/json:
schema:
type: object
/radio_presets:
get:
tags: [System]
summary: Get radio presets
responses:
'200':
description: Preset list
content:
application/json:
schema:
type: object
/serial_ports:
get:
tags: [System]
summary: List available serial ports
responses:
'200':
description: Serial ports
content:
application/json:
schema:
type: object
/setup_wizard:
post:
tags: [System]
summary: Submit setup wizard payload
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Setup applied
content:
application/json:
schema:
type: object
/check_pymc_console:
get:
tags: [System]
summary: Check pyMC console availability
responses:
'200':
description: Console status
content:
application/json:
schema:
type: object
/mqtt_status:
get:
tags: [System]
summary: Get MQTT runtime status
responses:
'200':
description: MQTT status
content:
application/json:
schema:
type: object
/broker_presets:
get:
tags: [System]
summary: List MQTT broker presets
responses:
'200':
description: Broker presets
content:
application/json:
schema:
type: object
/update_web_config:
post:
tags: [System]
summary: Update web configuration
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Web config updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/update_mqtt_config:
post:
tags: [System]
summary: Update MQTT configuration
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: MQTT config updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/update_advert_rate_limit_config:
post:
tags: [Adverts]
summary: Update advert rate limit configuration
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Advert rate limit config updated
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
/bulk_packets:
get:
tags: [Packets]
summary: Fetch packets in bulk
parameters:
- name: limit
in: query
schema:
type: integer
default: 1000
- name: offset
in: query
schema:
type: integer
default: 0
- name: start_timestamp
in: query
schema:
type: number
- name: end_timestamp
in: query
schema:
type: number
responses:
'200':
description: Bulk packet result
content:
application/json:
schema:
type: object
/airtime_data:
get:
tags: [Packets]
summary: Get lightweight airtime packet rows
parameters:
- name: start_timestamp
in: query
schema:
type: number
- name: end_timestamp
in: query
schema:
type: number
- name: limit
in: query
schema:
type: integer
default: 50000
responses:
'200':
description: Airtime data rows
content:
application/json:
schema:
type: object
/airtime_chart_data:
get:
tags: [Charts]
summary: Get server-aggregated airtime chart buckets
parameters:
- name: start_timestamp
in: query
schema:
type: number
- name: end_timestamp
in: query
schema:
type: number
- name: bucket_seconds
in: query
schema:
type: integer
default: 60
- name: sf
in: query
schema:
type: integer
default: 9
- name: bw_hz
in: query
schema:
type: integer
default: 62500
- name: cr
in: query
schema:
type: integer
default: 5
- name: preamble
in: query
schema:
type: integer
default: 17
responses:
'200':
description: Airtime buckets
content:
application/json:
schema:
type: object
/adverts_count_by_contact_type:
get:
tags: [Adverts]
summary: Get advert count for contact type
parameters:
- name: contact_type
in: query
required: true
schema:
type: string
- name: hours
in: query
schema:
type: integer
responses:
'200':
description: Advert count
content:
application/json:
schema:
type: object
/advert_rate_limit_stats:
get:
tags: [Adverts]
summary: Get advert rate-limit runtime stats
responses:
'200':
description: Rate-limit stats
content:
application/json:
schema:
type: object
/crc_error_count:
get:
tags: [System]
summary: Get CRC error count
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
responses:
'200':
description: CRC error count
content:
application/json:
schema:
type: object
/crc_error_history:
get:
tags: [System]
summary: Get CRC error history
parameters:
- name: hours
in: query
schema:
type: integer
default: 24
- name: limit
in: query
schema:
type: integer
responses:
'200':
description: CRC error records
content:
application/json:
schema:
type: object
/memory_debug:
get:
tags: [System]
summary: Get memory diagnostics
responses:
'200':
description: Memory diagnostics
content:
application/json:
schema:
type: object
post:
tags: [System]
summary: Start/stop memory diagnostics tracing
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
action:
type: string
enum: [start, stop]
responses:
'200':
description: Tracing state changed
content:
application/json:
schema:
type: object
/config_export:
get:
tags: [System]
summary: Export configuration
parameters:
- name: include_secrets
in: query
schema:
type: boolean
responses:
'200':
description: Exported config payload
content:
application/json:
schema:
type: object
required: [success, data]
properties:
success:
type: boolean
data:
type: object
required: [meta, config]
properties:
meta:
type: object
required: [exported_at, version, config_path, includes_secrets]
properties:
exported_at:
type: string
format: date-time
version:
type: string
config_path:
type: string
includes_secrets:
type: boolean
config:
type: object
error:
type: string
/config_import:
post:
tags: [System]
summary: Import configuration
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Import result
content:
application/json:
schema:
type: object
/identity_export:
get:
tags: [Identities]
summary: Export repeater identity key
responses:
'200':
description: Identity export
content:
application/json:
schema:
type: object
required: [success, data]
properties:
success:
type: boolean
data:
type: object
required: [identity_key_hex, key_length_bytes]
properties:
identity_key_hex:
type: string
key_length_bytes:
type: integer
public_key_hex:
type: string
node_address:
type: string
error:
type: string
/generate_vanity_key:
post:
tags: [Identities]
summary: Generate vanity identity key
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [prefix]
properties:
prefix:
type: string
minLength: 1
maxLength: 8
apply:
type: boolean
responses:
'200':
description: Vanity key generation result
content:
application/json:
schema:
type: object
required: [success, data]
properties:
success:
type: boolean
data:
type: object
required: [public_hex, private_hex, attempts]
properties:
public_hex:
type: string
private_hex:
type: string
attempts:
type: integer
applied:
type: boolean
error:
type: string
/db_stats:
get:
tags: [System]
summary: Get database statistics
responses:
'200':
description: Database stats
content:
application/json:
schema:
type: object
required: [success, data]
properties:
success:
type: boolean
data:
type: object
required: [database_size_bytes, rrd_size_bytes, tables]
properties:
database_size_bytes:
type: integer
rrd_size_bytes:
type: integer
tables:
type: array
items:
type: object
required: [name, row_count, has_timestamp]
properties:
name:
type: string
row_count:
type: integer
oldest_timestamp:
type: number
newest_timestamp:
type: number
has_timestamp:
type: boolean
error:
type: string
/db_purge:
post:
tags: [System]
summary: Purge database tables
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Table purge result
content:
application/json:
schema:
type: object
required: [success, data, message]
properties:
success:
type: boolean
data:
type: object
additionalProperties:
type: object
properties:
deleted:
type: integer
error:
type: string
message:
type: string
error:
type: string
/db_vacuum:
post:
tags: [System]
summary: Vacuum SQLite database
responses:
'200':
description: Vacuum result
content:
application/json:
schema:
type: object
required: [success, data]
properties:
success:
type: boolean
data:
type: object
required: [size_before, size_after, freed_bytes]
properties:
size_before:
type: integer
size_after:
type: integer
freed_bytes:
type: integer
error:
type: string
/docs:
get:
tags: [System]
summary: Serve Swagger UI docs page
responses:
'200':
description: HTML docs page
/api/auth/tokens:
get:
tags: [Authentication]
summary: List API tokens (alias path)
responses:
'200':
description: Token list
content:
application/json:
schema:
type: object
post:
tags: [Authentication]
summary: Create API token (alias path)
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Token created
content:
application/json:
schema:
type: object
/api/auth/tokens/{token_id}:
delete:
tags: [Authentication]
summary: Revoke API token (alias path)
parameters:
- name: token_id
in: path
required: true
schema:
type: integer
responses:
'200':
description: Token revoked
content:
application/json:
schema:
type: object
/companion:
get:
tags: [System]
summary: List companion bridge instances
responses:
'200':
description: Companion instances
content:
application/json:
schema:
type: object
/companion/self_info:
get:
tags: [System]
summary: Get local companion identity info
responses:
'200':
description: Companion identity
content:
application/json:
schema:
type: object
/companion/contacts:
get:
tags: [System]
summary: List companion contacts
responses:
'200':
description: Contacts
content:
application/json:
schema:
type: object
/companion/contact:
get:
tags: [System]
summary: Get one companion contact
parameters:
- name: pub_key
in: query
required: true
schema:
type: string
responses:
'200':
description: Contact detail
content:
application/json:
schema:
type: object
/companion/import_repeater_contacts:
post:
tags: [System]
summary: Import repeater adverts into companion contacts
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Import result
content:
application/json:
schema:
type: object
/companion/channels:
get:
tags: [System]
summary: List companion channels
responses:
'200':
description: Channels
content:
application/json:
schema:
type: object
/companion/stats:
get:
tags: [System]
summary: Get companion stats
responses:
'200':
description: Companion stats
content:
application/json:
schema:
type: object
/companion/send_text:
post:
tags: [System]
summary: Send direct text message via companion
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Send result
content:
application/json:
schema:
type: object
/companion/send_channel_message:
post:
tags: [System]
summary: Send channel message via companion
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Send result
content:
application/json:
schema:
type: object
/companion/login:
post:
tags: [System]
summary: Initiate companion login flow
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Login result
content:
application/json:
schema:
type: object
/companion/request_status:
post:
tags: [System]
summary: Request companion status frame
responses:
'200':
description: Request accepted
content:
application/json:
schema:
type: object
/companion/request_telemetry:
post:
tags: [System]
summary: Request companion telemetry frame
responses:
'200':
description: Request accepted
content:
application/json:
schema:
type: object
/companion/send_command:
post:
tags: [System]
summary: Send command to companion
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Command result
content:
application/json:
schema:
type: object
/companion/reset_path:
post:
tags: [System]
summary: Reset companion route/path state
responses:
'200':
description: Path reset
content:
application/json:
schema:
type: object
/companion/set_advert_name:
post:
tags: [System]
summary: Set companion advert name
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Name updated
content:
application/json:
schema:
type: object
/companion/set_advert_location:
post:
tags: [System]
summary: Set companion advert location
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Location updated
content:
application/json:
schema:
type: object
/companion/events:
get:
tags: [System]
summary: Stream companion events (SSE)
responses:
'200':
description: Event stream
/update/status:
get:
tags: [System]
summary: Get update service status
responses:
'200':
description: Update status
content:
application/json:
schema:
type: object
/update/check:
get:
tags: [System]
summary: Trigger or fetch update check
responses:
'200':
description: Check result
content:
application/json:
schema:
type: object
post:
tags: [System]
summary: Trigger update check
requestBody:
required: false
content:
application/json:
schema:
type: object
responses:
'200':
description: Check started/result
content:
application/json:
schema:
type: object
/update/install:
post:
tags: [System]
summary: Install available update
requestBody:
required: false
content:
application/json:
schema:
type: object
responses:
'200':
description: Install started
content:
application/json:
schema:
type: object
/update/progress:
get:
tags: [System]
summary: Stream update progress (SSE)
responses:
'200':
description: Progress event stream
/update/channels:
get:
tags: [System]
summary: List update channels
responses:
'200':
description: Available channels
content:
application/json:
schema:
type: object
/update/set_channel:
post:
tags: [System]
summary: Set update channel
requestBody:
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: Channel changed
content:
application/json:
schema:
type: object
/update/changelog:
get:
tags: [System]
summary: Get update changelog
responses:
'200':
description: Changelog content
content:
application/json:
schema:
type: object
/cli:
post:
tags: [System]
summary: Execute repeater CLI command
security:
- BearerAuth: []
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [command]
properties:
command:
type: string
responses:
'200':
description: CLI command result
content:
application/json:
schema:
type: object
components:
schemas:
SuccessResponse:
type: object
properties:
success:
type: boolean
example: true
data:
type: object
description: Response data (varies by endpoint)
ErrorResponse:
type: object
properties:
success:
type: boolean
example: false
error:
type: string
description: Error message
RoomMessage:
type: object
required: [id, author_pubkey, post_timestamp, message_text, txt_type]
properties:
id:
type: integer
description: Database message ID
example: 123
author_pubkey:
type: string
pattern: '^[0-9a-fA-F]{64}$|^00{64}$'
description: |
Author's public key (64 hex chars):
- 32 zeros (64 '0's) = server/system message
- Other hex = regular user message
example: "abc123def456..."
author_prefix:
type: string
pattern: '^[0-9a-fA-F]{8}$'
description: First 8 chars of author_pubkey (for display)
example: "abc123de"
post_timestamp:
type: number
format: float
description: Server timestamp when message was stored (Unix epoch)
example: 1734567890.5
sender_timestamp:
type: integer
description: Client-provided timestamp (may be inaccurate)
example: 1734567890
message_text:
type: string
maxLength: 160
description: Message content (auto-truncated at 160 bytes)
example: "Hello world"
txt_type:
type: integer
enum: [0, 2]
description: |
Message type:
- 0: Plain text
- 2: Signed plain text
example: 0
created_at:
type: number
format: float
description: Database insertion timestamp (Unix epoch)
example: 1734567890.5
RoomClient:
type: object
required: [pubkey, sync_since, unsynced_count, is_active]
properties:
pubkey:
type: string
pattern: '^[0-9a-fA-F]{64}$'
description: Client's public key (64 hex chars)
example: "abc123def456..."
pubkey_prefix:
type: string
pattern: '^[0-9a-fA-F]{8}$'
description: First 8 chars of pubkey (for display)
example: "abc123de"
sync_since:
type: number
format: float
description: Last sync timestamp (Unix epoch)
example: 1734567890.5
unsynced_count:
type: integer
minimum: 0
maximum: 32
description: Number of new messages for this client (max 32, messages NOT sent to author)
example: 5
pending_ack:
type: boolean
description: Waiting for ACK from client
example: false
push_failures:
type: integer
minimum: 0
description: Number of failed delivery attempts
example: 0
last_activity:
type: number
format: float
description: Last activity timestamp (Unix epoch)
example: 1734567890.5
in_acl:
type: boolean
description: Client passes ACL check
example: true
is_active:
type: boolean
description: Client is currently active (synced within timeout period)
example: true
Identity:
type: object
required: [name, type, hash, public_key]
properties:
name:
type: string
minLength: 1
maxLength: 64
pattern: '^[a-zA-Z0-9_\-\s]+$'
description: Identity name (alphanumeric, spaces, hyphens, underscores)
example: "General Chat"
type:
type: string
enum: [repeater, room_server]
description: |
- repeater: Repeater identity (only one allowed per system)
- room_server: Room server for group chat
example: room_server
hash:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: 1-byte identity hash (used in radio packets)
example: "0x42"
public_key:
type: string
pattern: '^[0-9a-fA-F]{64}$'
description: Ed25519 public key (64 hex chars)
example: "abc123def456..."
settings:
type: object
description: Type-specific settings
properties:
admin_password:
type: string
minLength: 4
description: Admin password (room_server only)
example: "admin123"
guest_password:
type: string
minLength: 4
description: Guest password (room_server only)
example: "guest123"
max_posts:
type: integer
minimum: 1
maximum: 32
default: 32
description: Maximum messages to keep (room_server only, hard limit 32)
example: 32
ACLClient:
type: object
required: [public_key, public_key_full, address, permissions]
properties:
public_key:
type: string
description: Truncated public key for display (first 24 and last 8 chars)
example: "03ccf3bb0bed9a51...21416fff"
public_key_full:
type: string
pattern: '^[0-9a-fA-F]{64}$'
description: Full client public key (64 hex chars)
example: "03ccf3bb0bed9a5109868a1e33ed020519aab6dbb30e42df3b11a21d21416fff"
address:
type: string
description: Client address identifier
example: "e1"
permissions:
type: string
enum: [admin, guest, read_only]
description: |
Client permission level:
- admin: Full access
- guest: Limited access
- read_only: Read-only access
example: "admin"
last_activity:
type: integer
description: Unix timestamp of last activity
example: 1766065148
last_login_success:
type: integer
description: Unix timestamp of last successful login
example: 1766065146
last_timestamp:
type: integer
description: Unix timestamp from last client message
example: 1766065146
identity_name:
type: string
description: Name of the identity this client is authenticated to
example: "rrrrr"
identity_type:
type: string
enum: [repeater, room_server]
description: Type of identity
example: "room_server"
identity_hash:
type: string
pattern: '^0x[0-9a-fA-F]{2}$'
description: Hash of the identity
example: "0xC5"
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token authentication via Authorization header
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: API key authentication for machine-to-machine access
# Future security - currently open
# security:
# - ApiKeyAuth: []