This document provides comprehensive documentation for the MeshMonitor REST API.
- Development:
http://localhost:3001 - Production:
http://localhost:8080(when using Docker)
All API endpoints are prefixed with /api/.
Currently, MeshMonitor does not implement authentication. All endpoints are publicly accessible.
All API responses follow a consistent JSON format:
Success Response:
{
"data": { ... },
"status": "success"
}Error Response:
{
"error": "Error message description",
"status": "error"
}Retrieve all nodes from the database.
Response:
[
{
"nodeNum": 3748313172,
"user": {
"id": "!df6ab854",
"longName": "K4FAU",
"shortName": "K4FA",
"hwModel": 0
},
"position": {
"latitude": 25.7617,
"longitude": -80.1918,
"altitude": 10
},
"deviceMetrics": {
"batteryLevel": 95,
"voltage": 4.1,
"channelUtilization": 0.5,
"airUtilTx": 0.2
},
"lastHeard": 1758835127.284,
"snr": 8.5,
"rssi": -45
}
]Get nodes that have been active within a specified time frame.
Query Parameters:
days(optional): Number of days to look back (default: 7)
Example: /api/nodes/active?days=3
Response: Same format as /api/nodes
Get historical position data for a specific node.
Path Parameters:
nodeId: Node identifier (string, e.g., "!a2e4ff4c")
Query Parameters:
hours(optional): Hours of history to retrieve (default: 24)
Example: /api/nodes/!a2e4ff4c/position-history?hours=48
Response:
[
{
"timestamp": 1640995200000,
"latitude": 25.7617,
"longitude": -80.1918,
"altitude": 10
}
]Toggle favorite status for a node.
Path Parameters:
nodeId: Node identifier (string, e.g., "!a2e4ff4c")
Request Body:
{
"isFavorite": true
}Response:
{
"success": true,
"nodeNum": 2732916556,
"isFavorite": true
}Error Responses:
400: Missing or invalid isFavorite value or invalid nodeId format500: Failed to set node favorite
Notes:
- Favorite nodes appear at the top of node lists regardless of sorting
- Favorite status syncs with Meshtastic device's NodeDB via NodeInfo packets
- Frontend displays star icons (⭐ for favorited, ☆ for not favorited)
Retrieve messages with pagination support.
Query Parameters:
limit(optional): Maximum number of messages to return (default: 100)offset(optional): Number of messages to skip (default: 0)
Example: /api/messages?limit=50&offset=100
Response:
[
{
"id": "msg_1234567890",
"from": "!df6ab854",
"to": "!ffffffff",
"text": "Hello mesh network!",
"channel": 0,
"portnum": 1,
"timestamp": "2024-01-15T10:30:00.000Z",
"rxTime": 1642248600000,
"createdAt": 1642248600000
}
]Send a text message to a channel.
Request Body:
{
"text": "Hello mesh network!",
"channel": 0
}Response:
{
"success": true
}Error Responses:
400: Missing or invalid message text500: Failed to send message
Get messages from a specific channel.
Path Parameters:
channel: Channel number (integer)
Query Parameters:
limit(optional): Maximum messages to return (default: 100)
Example: /api/messages/channel/0?limit=20
Response: Same format as /api/messages
Get direct messages between two nodes.
Path Parameters:
nodeId1: First node ID (string)nodeId2: Second node ID (string)
Query Parameters:
limit(optional): Maximum messages to return (default: 100)
Example: /api/messages/direct/!df6ab854/!a2e4ff4c
Response: Same format as /api/messages
Retrieve all configured channels.
Response:
[
{
"id": 0,
"name": "Primary",
"psk": null,
"uplinkEnabled": true,
"downlinkEnabled": true,
"createdAt": 1642248600000,
"updatedAt": 1642248600000
},
{
"id": 1,
"name": "admin",
"psk": "encrypted_key",
"uplinkEnabled": true,
"downlinkEnabled": true,
"createdAt": 1642248600000,
"updatedAt": 1642248600000
}
]Get recently collected traceroute data with route paths and SNR information.
Query Parameters:
hours(optional): Hours to look back (default: 24)limit(optional): Maximum number of traceroutes to return (default: 100)
Example: /api/traceroutes/recent?hours=12&limit=50
Response:
[
{
"id": 1,
"fromNodeNum": 123456789,
"toNodeNum": 987654321,
"fromNodeId": "!075bcd15",
"toNodeId": "!3ade68b1",
"route": "[123456789,555555555,987654321]",
"routeBack": "[987654321,555555555,123456789]",
"snrTowards": "[12.5,8.3,10.1]",
"snrBack": "[10.5,9.2,11.3]",
"timestamp": 1640995200000,
"createdAt": 1640995201000
}
]Send a traceroute request to a specific node.
Request Body:
{
"destination": "!3ade68b1"
}Response:
{
"success": true,
"message": "Traceroute sent to !3ade68b1"
}Error Responses:
400: Missing or invalid destination node ID500: Failed to send traceroute
Health check endpoint for monitoring system status.
Response:
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00.000Z",
"nodeEnv": "production"
}Get the current Meshtastic node connection status.
Response:
{
"connected": true,
"nodeIp": "192.168.1.100"
}Get application configuration.
Response:
{
"meshtasticNodeIp": "192.168.1.100",
"meshtasticUseTls": false
}Get Meshtastic device configuration.
Response:
{
"basic": {
"nodeAddress": "192.168.1.100",
"useTls": false,
"connected": true
},
"radio": {
"region": "US",
"modemPreset": "Medium_Fast",
"hopLimit": 3,
"txPower": 30,
"bandwidth": 250,
"spreadFactor": 9,
"codingRate": 8
},
"mqtt": {
"enabled": true,
"server": "mqtt.areyoumeshingwith.us",
"username": "uplink",
"encryption": true,
"json": true,
"tls": true,
"rootTopic": "msh"
},
"channels": [
{
"index": 0,
"name": "Primary",
"psk": "None",
"uplinkEnabled": true,
"downlinkEnabled": true
}
]
}Get database and network statistics.
Response:
{
"messageCount": 1250,
"nodeCount": 45,
"channelCount": 4,
"messagesByDay": [
{
"date": "2024-01-15",
"count": 125
},
{
"date": "2024-01-14",
"count": 98
}
]
}Export all database data for backup purposes.
Response:
{
"nodes": [ ... ],
"messages": [ ... ]
}Note: Response can be large depending on database size.
Import data to restore from backup.
Request Body:
{
"nodes": [ ... ],
"messages": [ ... ]
}Response:
{
"success": true
}Warning: This operation will clear existing data before importing.
Clean up old messages from the database.
Request Body:
{
"days": 30
}Response:
{
"deletedCount": 145
}Clean up inactive nodes from the database.
Request Body:
{
"days": 30
}Response:
{
"deletedCount": 12
}Clean up invalid channels from the database.
Response:
{
"deletedCount": 8
}200- Success400- Bad Request (invalid parameters)404- Not Found500- Internal Server Error503- Service Unavailable (Meshtastic node unreachable)
"Failed to fetch nodes"- Database error when retrieving nodes"Failed to send message"- Error communicating with Meshtastic node"Message text is required"- Missing required message text in request"Unable to retrieve device configuration"- Meshtastic node communication error"Failed to cleanup [resource]"- Database error during cleanup operations
Currently, no rate limiting is implemented. Consider implementing rate limiting for production deployments.
WebSocket support is planned for future releases to provide real-time updates without polling.
interface DeviceInfo {
nodeNum: number;
user?: {
id: string;
longName: string;
shortName: string;
hwModel?: number;
role?: number;
};
hopsAway?: number;
position?: {
latitude: number;
longitude: number;
altitude?: number;
};
deviceMetrics?: {
batteryLevel?: number;
voltage?: number;
channelUtilization?: number;
airUtilTx?: number;
};
lastHeard?: number;
snr?: number;
rssi?: number;
firmwareVersion?: string;
isMobile?: boolean;
isFavorite?: boolean; // Synced from Meshtastic device NodeDB
}interface MeshMessage {
id: string;
from: string;
to: string;
text: string;
channel: number;
portnum?: number;
timestamp: Date;
rxTime?: number;
createdAt: number;
}interface Channel {
id: number;
name: string;
psk?: string;
uplinkEnabled: boolean;
downlinkEnabled: boolean;
createdAt: number;
updatedAt: number;
}// Fetch all nodes
const response = await fetch('/api/nodes');
const nodes = await response.json();
// Send a message
const response = await fetch('/api/messages/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: 'Hello mesh!',
channel: 0
})
});
// Get channel messages
const response = await fetch('/api/messages/channel/0?limit=50');
const messages = await response.json();# Get all nodes
curl http://localhost:8080/api/nodes
# Send a message
curl -X POST http://localhost:8080/api/messages/send \
-H "Content-Type: application/json" \
-d '{"text":"Hello mesh!","channel":0}'
# Get statistics
curl http://localhost:8080/api/stats
# Cleanup old messages
curl -X POST http://localhost:8080/api/cleanup/messages \
-H "Content-Type: application/json" \
-d '{"days":30}'
# Get recent traceroutes
curl http://localhost:8080/api/traceroutes/recent?hours=24
# Send traceroute to a node
curl -X POST http://localhost:8080/api/traceroutes/send \
-H "Content-Type: application/json" \
-d '{"destination":"!12345678"}'
# Set node as favorite
curl -X POST http://localhost:8080/api/nodes/!a2e4ff4c/favorite \
-H "Content-Type: application/json" \
-d '{"isFavorite":true}'
# Remove node from favorites
curl -X POST http://localhost:8080/api/nodes/!a2e4ff4c/favorite \
-H "Content-Type: application/json" \
-d '{"isFavorite":false}'When developing with the API:
- CORS: Enabled for all origins in development
- Hot Reload: Server restarts automatically during development
- Logging: All requests/responses are logged to console
- Error Handling: Comprehensive error logging for debugging
- Input Validation: All inputs are validated before processing
- SQL Injection: Prevented through parameterized queries
- XSS Protection: Text content is properly sanitized
- CORS Policy: Configure appropriately for production
For more information, see the Architecture Documentation and README.