name: mesh-api
description: Interact with a Meshtastic LoRa mesh network through MESH-API — list nodes, read messages, send texts, and check connection status.
version: 1.0.0
author: mesh-api community
metadata:
openclaw:
required_env:
- MESH_API_URL
- MESH_API_KEY
required_bins:
- curl
tags:
- meshtastic
- mesh
- radio
- iot
- lora
MESH-API Skill
You can interact with a Meshtastic LoRa mesh network through a running MESH-API instance.
MESH-API exposes a REST API (default port 5000) that lets you list online nodes, read recent messages, send texts to specific nodes or broadcast to channels, and check device connectivity.
Configuration
MESH_API_URL— Base URL of the MESH-API instance (e.g.http://192.168.1.50:5000). Required.MESH_API_KEY— Optional bearer token for future authentication support. If set, include it asAuthorization: Bearer <token>on every request. If empty or unset, omit the header entirely — MESH-API has no auth by default.
Available Endpoints
GET /nodes
List all mesh nodes the MESH-API instance can see.
Request:
curl -s "$MESH_API_URL/nodes"
Response: JSON array of node objects.
[
{"id": "!a1b2c3d4", "shortName": "TBot", "longName": "TBot Base Station"},
{"id": "!e5f6a7b8", "shortName": "Hike", "longName": "Hiker Node"}
]
idis the Meshtastic hex node ID (always starts with!followed by 8 hex characters).shortNameis a 4-character display name.longNameis the full node name.
GET /messages
Retrieve recent messages from the mesh.
Request:
curl -s "$MESH_API_URL/messages"
Response: JSON array of message objects. Each message contains sender info, text, timestamp, and channel.
POST /send
Send a message to a specific node (direct) or broadcast to a channel.
Direct message to a node:
curl -s -X POST "$MESH_API_URL/send" \
-H "Content-Type: application/json" \
-d '{"message": "Hello from OpenClaw", "node_id": "!a1b2c3d4", "direct": true}'
Broadcast to a channel:
curl -s -X POST "$MESH_API_URL/send" \
-H "Content-Type: application/json" \
-d '{"message": "Hello mesh!", "channel_index": 0}'
Body parameters:
message(string, required) — The text to send.node_id(string, required for direct) — Target node hex ID (e.g.!a1b2c3d4).direct(boolean) — Settruefor a direct message tonode_id.channel_index(integer) — Channel index for broadcast (default0= LongFast).
Response:
{"status": "sent", "to": "!a1b2c3d4", "direct": true, "message": "Hello from OpenClaw"}
POST /ui_send
Broadcast a message to a channel (form-encoded, primarily used by the web UI).
Request:
curl -s -X POST "$MESH_API_URL/ui_send" \
-d "message=Hello+mesh!&channel_index=0"
Parameters (form-encoded):
message(string, required) — The text to send.channel_index(integer) — Channel index (default0).destination_node(string, optional) — If provided, sends a direct message instead of broadcast.
For programmatic use, prefer POST /send with JSON. Use /ui_send only when mimicking the web UI.
GET /connection_status
Check whether MESH-API is connected to its Meshtastic radio device.
Request:
curl -s "$MESH_API_URL/connection_status"
Response:
{"status": "connected", "error": null}
statuswill be"connected"or"disconnected".errorcontains an error description string if disconnected, otherwisenull.
GET /commands_info
List all available slash commands registered on the mesh (including extension commands).
Request:
curl -s "$MESH_API_URL/commands_info"
Response: JSON array of command objects.
[
{"command": "/ping", "description": "Check if the bot is online"},
{"command": "/ai-9z", "description": "Ask the AI a question"},
{"command": "/nodes", "description": "List online mesh nodes"}
]
Natural Language Examples
When the user says something like the phrases below, map their intent to the corresponding API call:
| User says | Action |
|-----------|--------|
| "Who is online on the mesh?" | GET /nodes — list all visible nodes and summarize who is online. |
| "What nodes are on the mesh network?" | GET /nodes |
| "Send 'hello' to TBot" | GET /nodes first to resolve the name "TBot" to a node ID, then POST /send with {"message": "hello", "node_id": "<resolved_id>", "direct": true}. |
| "Send a message to !a1b2c3d4" | POST /send with {"message": "<user's message>", "node_id": "!a1b2c3d4", "direct": true}. |
| "What's been said on the mesh recently?" | GET /messages — retrieve and summarize the recent messages. |
| "Show me mesh messages" | GET /messages |
| "Is the mesh connected?" | GET /connection_status — report whether the radio link is up. |
| "Check mesh connection" | GET /connection_status |
| "Broadcast 'weather alert' to the mesh" | POST /send with {"message": "weather alert", "channel_index": 0}. |
| "Broadcast on channel 2: meeting at noon" | POST /send with {"message": "meeting at noon", "channel_index": 2}. |
| "What commands does the mesh bot support?" | GET /commands_info — list and describe available slash commands. |
When resolving a node by name (e.g. "send to TBot"), always call GET /nodes first to find the matching id. Never guess a node ID.
IMPORTANT CONSTRAINTS
Character limit. Meshtastic mesh messages have a strict practical limit. Keep any message you send via
POST /sendunder 200 characters unless the user explicitly requests a longer message. MESH-API will chunk longer messages automatically, but each chunk is a separate radio transmission — warn the user it will arrive as multiple packets and may take time.No unsolicited long messages. Never send AI-generated text directly to the mesh without user confirmation if the text exceeds one chunk (200 characters). Always ask the user first: "This response is X characters and will be sent as N packets — proceed?"
Bot-loop prevention. Messages prefixed with
m@i-are AI-generated mesh messages. If you see this prefix on an inbound mesh message (viaGET /messages), do not relay it back to the mesh. Doing so creates an infinite loop between AI agents on the network.Node ID format. Meshtastic node IDs are hex strings matching the pattern
!followed by exactly 8 hexadecimal characters (e.g.!a1b2c3d4). Always validate a node ID matches this format before using it inPOST /send. If the user provides a name instead, resolve it viaGET /nodes.Connection check. Before sending messages, it is good practice to call
GET /connection_statusto verify the mesh radio is connected. If status is"disconnected", inform the user and do not attempt to send.No auth by default. MESH-API does not require authentication in its default configuration. The
MESH_API_KEYenv var is optional future-proofing. Only include theAuthorizationheader ifMESH_API_KEYis set and non-empty.Rate awareness. Meshtastic is a low-bandwidth LoRa network. Do not send rapid bursts of messages. If you need to send multiple messages, space them out and inform the user about the delay.