mirror of
https://github.com/rightup/pyMC_Repeater.git
synced 2026-03-28 17:43:06 +01:00
- Added functionality to heal companion registration names with empty values. - Improved handling of identity keys and public key derivation for companions. - Updated API endpoints to support companion identity lookups using name, lookup_identity_key, or public_key_prefix. - Enhanced OpenAPI documentation to clarify requirements for identity creation, updates, and deletions, including trimming whitespace from names.
2512 lines
76 KiB
YAML
2512 lines
76 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: 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"
|
|
|
|
/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
|
|
|
|
/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'
|
|
|
|
/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:
|
|
get:
|
|
tags: [Adverts]
|
|
summary: Get specific advert
|
|
description: Retrieve details of a specific advertisement
|
|
parameters:
|
|
- name: advert_id
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
description: Advert ID to retrieve
|
|
responses:
|
|
'200':
|
|
description: Advert details
|
|
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
|
|
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
|
|
# ============================================================================
|
|
/global_flood_policy:
|
|
get:
|
|
tags: [Network Policy]
|
|
summary: Get global flood policy
|
|
description: Retrieve current network flood policy configuration
|
|
security:
|
|
- BearerAuth: []
|
|
- ApiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: Current policy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
post:
|
|
tags: [Network Policy]
|
|
summary: Update global 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
|
|
properties:
|
|
node_id:
|
|
type: string
|
|
description: Target node identifier
|
|
responses:
|
|
'200':
|
|
description: Ping sent
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SuccessResponse'
|
|
|
|
# ============================================================================
|
|
# Identity Management
|
|
# ============================================================================
|
|
/create_identity:
|
|
post:
|
|
tags: [Identities]
|
|
summary: Create new identity
|
|
description: |
|
|
Create a new repeater 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}$'
|
|
description: 32-byte hex key (64 chars). Omit for auto-generation
|
|
example: "abc123def456..."
|
|
type:
|
|
type: string
|
|
enum: [repeater, room_server]
|
|
description: |
|
|
- repeater: Repeater identity (only one allowed)
|
|
- 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
|
|
examples:
|
|
room_server:
|
|
value:
|
|
name: "General Chat"
|
|
type: room_server
|
|
settings:
|
|
admin_password: "admin123"
|
|
guest_password: "guest123"
|
|
max_posts: 32
|
|
repeater:
|
|
value:
|
|
name: "My Repeater"
|
|
type: repeater
|
|
identity_key: "abc123def456..."
|
|
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
|
|
|
|
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: []
|