Skip to main content

restmesh

PyPI restmesh version Downloads Buy me a coffee M-Powered FastAPI

A stateless thread-safe REST API for Meshtastic.

image

Description and features

Send messages on Meshtastic using a standard REST API:

  • thread safe via asyncio
  • safe because a FIFO queue avoid overwhelming the mesh
  • very simple to integrate in other projects: Apprise is already available
  • aims to have 100% unit test coverage
  • doesn't use a database, it merely acts as a gateway
  • no MQTT, WiFI, bluetooth: just plug in the radio via USB, set it as CLIENT_MUTE and enjoy

Examples

Error reporting: is Internet down?

A typical use case for restmesh is for system error reporting, for example when local Internet is down. You could set up a script to interface with restmesh like how I described in Automatic alerts and news on Meshtastic - part 1

RSS/Atom feeds to mesh: weather warnings

You can also resyndicate RSS/Atom feeds to Meshtastic using a third party program called feed2exec. You can add as many feeds as you like and schedule the feed fetching via some cron. See the Automatic alerts and news on Meshtastic - part 2 post.

Quickstart

One minute setup

  1. install pipx

  2. install restmesh

    pipx install restmesh
    
  3. your user must have access to the modem. For example on Debian you have to add your user to the dialout group

    sudo usermod -aG dialout ${USER}
    
  4. run restmesh

    restmesh
    
  5. connect to the /docs page using a browser

  6. create a Systemd service

    [Unit]
    Requires=network-online.target
    After=network-online.target
    
    [Service]
    User=meshtastic
    Group=meshtastic
    Type=simple
    ExecStart=/bin/restmesh
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target
    

[!IMPORTANT] The modem device may be different that the default one, /dev/ttyUSB0. Check new devices with dmesg. In some cases it might be /dev/ttyACM0 instead. Naming depdends from different loaded kernel modules.

CLI help

usage: restmesh [-h] [--version] [--host HOST] [--port PORT] [--radio-serial-path RADIO_SERIAL_PATH]

restmesh: stateless thread-safe REST API for Meshtastic

options:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  --host HOST           server host listening address (default: 127.0.0.1)
  --port PORT           server listening port (default: 8000)
  --radio-serial-path RADIO_SERIAL_PATH
                        path of the USB serial device radio (default: /dev/ttyUSB0)

Running

Defaults

restmesh --host 127.0.0.1 --port 8000 --radio-serial-path /dev/ttyUSB0

Connect to http://127.0.0.1:8000/docs for the Swagger page to test the endpoints, or use Apprise directly.

Globally

restmesh --host 0.0.0.0 --port 8000 --radio-serial-path /dev/ttyUSB0

[!WARNING] At the moment no kind of authentication is implemented!

Use the Core API

Send to channel 0 (the primary channel):

curl -X 'POST' \
'http://127.0.0.1:8000/api/v1/channels/0/messages' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "text": "This is a message for the mesh on channel 0!",
  "want_ack": false,
  "port_num": 1
}'

Send to node !0a1b2c3d:

curl -X 'POST' \
  'http://127.0.0.1:8000/api/v1/nodes/%210a1b2c3d/messages' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "text": "This is a message for node !0a1b2c3d",
  "want_ack": false,
  "want_response": true,
  "port_num": 1
}'

Integrations

Apprise

restmesh accepts Apprise via the JSON schema. To be able to use it you need to install it first. See also the Repology page to see the available packages for Apprise.

[!NOTE] The title parameter is ignored! Write your full text in the body.

Channel

Simple example using channel 0:

apprise -b 'My message here' "json://localhost:8000/api/v1/integrations/apprise/channels/0/messages"

With parameters:

apprise -b 'Hello world!' "json://localhost:8000/api/v1/integrations/apprise/channels/0/messages?:wantAck=false&:portNum=1"

Node

Send a message to the node with hex id !0a1b2c3d. Alternatively you can use the decimal integer representation of the node id, without prepending the ! character:

apprise -b 'My message here' "json://localhost:8000/api/v1/integrations/apprise/nodes/!0a1b2c3d/messages"

apprise -b 'My message here' "json://localhost:8000/api/v1/integrations/apprise/nodes/169552957/messages"

With parameters:

apprise -b 'Hello world!' "json://localhost:8000/api/v1/integrations/apprise/nodes/!0a1b2c3d/messages?:wantResponse=true&wantAck=false&:portNum=1"

apprise -b 'Hello world!' "json://localhost:8000/api/v1/integrations/apprise/nodes/169552957/messages?:wantResponse=true&wantAck=false&:portNum=1"

Contributing

See Contributing.

Responsible usage policy

Meshtastic

In some places, such as Europe, the non-ham LoRa band has limited air time use. Please don't use restmesh for mass spamming, and never broadcast automated messages on public channels such as MediumFast or LongFast. Setup private channels instead.

restmesh has a basic message FIFO queue also to mitigate the air time problem.

Consulting and custom integrations

If you need help or custom endpoints and integrations, I'm available for contract-based freelance consulting and custom Python development:

License

Copyright (C) 2026 Franco Masotti

restmesh is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

restmesh is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with restmesh. If not, see http://www.gnu.org/licenses/.

Changelog and trusted source

You can check the authenticity of new releases using my public key.

Changelogs, instructions, sources and keys can be found at blog.franco.net.eu.org/software/#restmesh.

Git forge mirrors

URL Type Notes
https://github.com/frnmst/restmesh RW Official home
https://codeberg.org/frnmst/restmesh RW Mirror
https://framagit.org/frnmst/restmesh RW Mirror
https://repos.franco.net.eu.org/frnmst/restmesh RW Mirror

Support this project

REST API reference

This endpoint documentation is automatically generated from FastAPI OpenAPI's generator and swagger-markdown.


[POST] /api/v1/channels/{channel_index}/messages

Send a message to a channel

Broadcast a text message to a specific mesh channel.

Parameters

Name Located in Description Required Schema
channel_index path The channel index (0 to 7) Yes integer

Request Body

Required Schema
Yes application/json: ChannelBroadcastPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

[POST] /api/v1/nodes/{node_target}/messages

Send Text To Node

Send a DM text to a node via nodeId string or nodeNum integer.

Parameters

Name Located in Description Required Schema
node_target path Target destination: can be a lowercase hex string NodeId (e.g. !2c3b4f5a) or a numeric NodeNum < 2^32 (e.g. 60). Yes string or integer

Request Body

Required Schema
Yes application/json: NodeDirectPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

[POST] /api/v1/integrations/apprise/channels/{channel_index}/messages

Apprise Gateway Adapter Send Text Channel

Adapter gateway.

Parameters

Name Located in Description Required Schema
channel_index path The channel index (0 to 7) Yes integer

Request Body

Required Schema
Yes application/json: AppriseJsonChannelBroadcastPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

[POST] /api/v1/integrations/apprise/nodes/{node_target}/messages

Apprise Gateway Adapter Send Text Node

Adapter gateway.

Parameters

Name Located in Description Required Schema
node_target path Target destination: can be a lowercase hex string NodeId (e.g. !2c3b4f5a) or a numeric NodeNum < 2^32 (e.g. 60). Yes string or integer

Request Body

Required Schema
Yes application/json: AppriseJsonNodeDirectPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

Schemas

AppriseJsonChannelBroadcastPayload Schema

Name Type Description Required
regex_subst RegexSubst or null No
version string Apprise JSON schema version Yes
title string or null Unused parameter No
message string UTF-8 text to the mesh. This API limits it to 200 bytes for safety, although the default Meshtastic MTU is 237 bytes Yes
type string,
Available values: "info", "warning", "success", "failure" or null
Unused parameter No
attachment [ ],
Default:
Unused parameter No
want_ack boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery). See this also No
port_num integer,
Default: 1
Protobuf application port number No

AppriseJsonNodeDirectPayload Schema

Name Type Description Required
regex_subst RegexSubst or null No
version string Apprise JSON schema version Yes
title string or null Unused parameter No
message string UTF-8 text to the mesh. This API limits it to 200 bytes for safety, although the default Meshtastic MTU is 237 bytes Yes
type string,
Available values: "info", "warning", "success", "failure" or null
Unused parameter No
attachment [ ],
Default:
Unused parameter No
want_ack boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery). See this also No
port_num integer,
Default: 1
Protobuf application port number No
want_response boolean,
Default: true
true if you want the service on the other side to send an application layer response. See this also No

ChannelBroadcastPayload Schema

Name Type Description Required
regex_subst RegexSubst or null No
text string UTF-8 text to the mesh. This API limits it to 200 bytes for safety, although the default Meshtastic MTU is 237 bytes Yes
want_ack boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery). See this also No
port_num integer,
Default: 1
Protobuf application port number No

HTTPValidationError Schema

Name Type Description Required
detail [ ValidationError ] No

MeshActionResponse Schema

Name Type Description Required
status string Always return "success" Yes
routing_mode string,
Available values: "broadcast", "direct"
Message routing type
Enum: "broadcast", "direct"
Yes
packet MeshPacketDetails Packet data from radios Yes
on_response_callback_payload object or null No
truncated boolean Message was truncated to Meshtastic MTU before being sent No

MeshPacketDetails Schema

Name Type Description Required
id integer Yes
from integer or string Yes
to integer or string Yes
channel integer The channel index (0 to 7) Yes
port_num integer Protobuf application port number Yes
text string The message sent to the mesh Yes
want_ack boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery). See this also No
want_response boolean,
Default: true
true if you want the service on the other side to send an application layer response. See this also No

NodeDirectPayload Schema

Name Type Description Required
regex_subst RegexSubst or null No
text string UTF-8 text to the mesh. This API limits it to 200 bytes for safety, although the default Meshtastic MTU is 237 bytes Yes
want_ack boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery). See this also No
port_num integer,
Default: 1
Protobuf application port number No
want_response boolean,
Default: true
true if you want the service on the other side to send an application layer response. See this also No

QueueErrorResponse Schema

Name Type Description Required
detail string,
Default: Unable to handle more requests, queue full.
No

RadioErrorResponse Schema

Name Type Description Required
detail string,
Default: Meshtastic radio problem
No

RegexSubst Schema

Name Type Description Required
pattern string A regex pattern to be matched against No
subst string What to replace the regex pattern with No

ValidationError Schema

Name Type Description Required
loc [ string or integer ] Yes
msg string Yes
type string Yes
input No
ctx object No

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

restmesh-0.4.0.tar.gz (34.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

restmesh-0.4.0-py3-none-any.whl (28.2 kB view details)

Uploaded Python 3

File details

Details for the file restmesh-0.4.0.tar.gz.

File metadata

  • Download URL: restmesh-0.4.0.tar.gz
  • Upload date:
  • Size: 34.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for restmesh-0.4.0.tar.gz
Algorithm Hash digest
SHA256 8bfe31755c6a14fcdd4f6dd9c3db521cd27ea90f2996582233ce6f9dc5e63f5c
MD5 50856728aa40fbc4593a3715bde7b06e
BLAKE2b-256 8d659cb878005e35901249e54399afa3633310da9667746d9e1ab42a04cac7cd

See more details on using hashes here.

File details

Details for the file restmesh-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: restmesh-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 28.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for restmesh-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04a5d4665d81cd7923fa409b8571749d6996e83138215e020cc7dfb6029763ba
MD5 921f2f86ffd944355b1c6f12e2e112c7
BLAKE2b-256 29f43bd7a8dbe24d0dd432600002eee96339bd7f7a7744988da1b61b0df9cfac

See more details on using hashes here.

Release history Release notifications | RSS feed

0.6.0

2 files

0.5.0

2 files

This release

0.4.0 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page