Dashboard API documentation
This documentation is for Husarnet Dashboard API v3, which is currently in Beta. If you want to try this one out, you need an account at the Beta Dashboard and Husarnet version 2.0.335 or later (nightly channel).
If you are looking for legacy API docs, please refer to Legacy Dashboard API documentation.
Introduction
If you want to automate some part of your Husarnet workflow, or simply prefer TUIs over modern webapps, you can utilize our HTTP API for fleet management. The API can do anything the Dashboard can do, as this is exactly the same API the Dashboard is using itself.
The API can be accessed in three ways:
- CLI - via Husarnet CLI commands like
husarnet group create(easiest, cross-platform, most user-friendly and strongly recommended); - Daemon-proxied - by sending HTTP requests to
/forwardendpoint in Husarnet Daemon API (those are signed by the Daemon and forwarded to the Dashboard API); - Direct with JWT - by sending HTTP requests to API endpoints directly (which requires authentication in separate microservice in order to obtain bearer token);
Setup and authentication
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
Ensure that on the machine you want to use the API from:
- You have administrator privileges;
- Husarnet is installed and connected to the Dashboard;
- The device has
AccountAdminflag enabled in the Dashboard;

Husarnet Daemon provides the authentication layer in this case, and this is happening transparently. You are good to go.
Remember only the administrator of the device can use the API. You can for example: prefix each command with sudo (Linux, MacOS), add your user to husarnet group (Linux) or use elevated command prompt (Windows).
Ensure that on the machine you want to use the API from:
- You have administrator privileges;
- cURL is installed (or equivalent HTTP client - examples use cURL)
- jq is installed (actually optional, but it is used in examples as it simplifies a lot of things)
- Husarnet is installed and connected to the Dashboard;
- The device has
AccountAdminflag enabled in the Dashboard;

Authentication to Dashboard API is provided by Husarnet Daemon, but you will need to authenticate yourself with the Daemon first (i.e. prove you have administrator privileges on the device).
Therefore, for every request provide Daemon API token. This can be obtained by reading /var/lib/husarnet/daemon_api_token (or %PROGRAMDATA%\Husarnet\daemon_api_token on Windows) file, which cannot be read by regular user. For example:
HUSARNET_SECRET=$(sudo cat /var/lib/husarnet/daemon_api_token)
Then you put secret either into special HTTP header X-Husarnet-Secret:
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" localhost:16216/api/forward/v3/web/groups
or as a query parameter secret:
curl -s localhost:16216/api/forward/v3/web/groups?secret=$HUSARNET_SECRET
16216 is the default port number of Husarnet Daemon's built-in HTTP server. This can be configured via an environment variable.
Ensure that:
- cURL is installed (or equivalent HTTP client - examples use cURL)
- jq is installed (actually optional, but it is used in examples as it simplifies a lot of things)
- your Husarnet Dashboard account has password login enabled (you won't be able to use this method if you login only via Google or Github OAuth)
To use the API you first need to obtain a token (JSON Web Token, or JWT in short) from the auth service. In order to get it, present your email and password to the auth service (https://auth.beta.husarnet.com), by sending HTTP request to the /token endpoint. Then extract access_token field from the output. Using curl and jq:
EMAIL=youremail@example.com
PASSWORD=your_husarnet_password
JSON_PAYLOAD=$(jq -n -c --arg email "$EMAIL" --arg password "$PASSWORD" '$ARGS.named')
curl -s -H"Content-Type: application/json" -d "$JSON_PAYLOAD" https://auth.beta.husarnet.com/token?grant_type=password | jq -r .access_token
You should see JSON Web token (refer to https://www.jwt.io/ for more info), which you can use in the requests. These tokens are valid for one hour, so if it expires you will need to get a new one.
Now you can use the API providing the JWT in the header, as it is often the case with REST APIs. Like so:
HUSARNET_JWT=<paste your JWT here>
curl -s -H"Authorization: Bearer $HUSARNET_JWT" https://api.beta.husarnet.com/v3/web/groups
General info
API responses are always JSON and follow the structure below:
{
"type": "success",
"errors": [],
"warnings": [],
"message": "OK",
"payload": {}
}
typecan besuccess,user_error(for example incorrect input parameters) orserver_error.errors,warningsandmessagewill contain additional information that you may examine to see what was the problem if the request failed.- actual thing you are requesting is in
payloadfield, which can be an object or an array of objects, depending on the endpoint.
Be aware of the non-traditional behavior! In case of recoverable/temporary server errors, API will return status 200 anyway and type will be set to server_error. Always check type field when consuming API responses.
If you use the CLI, you can add --json or -j parameter, as used in the examples below, to display full JSON output. In the examples we also use --indent-json or -i, which indents the JSON. Without this parameter JSON is outputted in the most compact form (machine-friendly).
Skipping --json parameter outputs tabular data intended for human glance and is not suitable for scripts.
Groups
Listing your groups
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i group ls
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" localhost:16216/api/forward/v3/web/groups
curl -s -H"Authorization: Bearer $HUSARNET_JWT" https://api.beta.husarnet.com/v3/web/groups
Example output:
{
"type": "success",
"errors": [],
"warnings": [],
"message": "OK",
"payload": [
{
"id": "36dc59ab-f75f-488d-86bf-e0696fb88eb0",
"emoji": "🪟",
"name": "main",
"comment": "",
"devices": [
{
"id": "c3ca3ded-02cd-4be3-b291-8a5576437fa0",
"ip": "fc94:dede:eeee:dede:eeee:dede:eeee:dede",
"emoji": "🤖",
"hostname": "macos-testing",
"userAgent": "Husarnet,MacOS,ARM64,2.0.330",
"comment": "",
"aliases": null,
"status": "on",
"lastContact": "2025-11-17T10:35:40.819937Z"
},
{
"id": "14fe531e-c72e-45b3-b3f5-17ca2188a4f5",
"ip": "fc94:dede:eeee:dede:eeee:dede:eeee:dede",
"emoji": "🤖",
"hostname": "gnaarmok",
"userAgent": "Husarnet,Linux,AMD64,2.0.333",
"comment": "",
"aliases": null,
"status": "off",
"lastContact": "2025-11-17T10:35:51.460052Z"
}
]
},
{
"id": "c1a307df-1285-4199-94ff-8d9ef6eb356f",
"emoji": "😄",
"name": "esp32-homelab",
"comment": "",
"devices": null
},
{
"id": "863d0102-8eda-4687-91ad-0f385c67d7b3",
"emoji": "🤖",
"name": "robots",
"comment": "",
"devices": null
}
]
}
Viewing a group
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i group show <group name or id>
You can provide group name as an argument here. The CLI will figure out the correct UUID. You can also provide group UUID directly.
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" localhost:16216/api/forward/v3/web/groups/<group id>
curl -s -H"Authorization: Bearer $HUSARNET_JWT" https://api.beta.husarnet.com/v3/web/groups/<group id>
Example output:
{
"type": "success",
"errors": [],
"warnings": [],
"message": "OK",
"payload": {
"group": {
"id": "36dc59ab-f75f-488d-86bf-e0696fb88eb0",
"emoji": "🪟",
"name": "main",
"comment": "",
"devices": [
{
"id": "14fe531e-c72e-45b3-b3f5-17ca2188a4f5",
"ip": "fc94:dede:eeee:dede:eeee:dede:eeee:dede",
"emoji": "🤖",
"hostname": "gnaarmok",
"userAgent": "Husarnet,Linux,AMD64,2.0.333",
"comment": "",
"aliases": null,
"status": "",
"lastContact": "2025-11-17T10:38:51.905168Z"
},
{
"id": "c3ca3ded-02cd-4be3-b291-8a5576437fa0",
"ip": "fc94:dede:eeee:dede:eeee:dede:eeee:dede",
"emoji": "🤖",
"hostname": "macos-testing",
"userAgent": "Husarnet,MacOS,ARM64,2.0.330",
"comment": "",
"aliases": null,
"status": "",
"lastContact": "2025-11-17T10:38:41.634217Z"
}
],
"joinCodes": null
},
"attachableDevices": [],
"joinCode": {
"token": "some_token"
}
}
}
Creating a new group
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i group create <group name>
Name is the only required parameter when creating a group. To set optional parameters, like comment, use flags (--emoji, --comment). For example:
husarnet --json -i group create new_group_name --comment "some comment"
JSON_PAYLOAD=$(jq -n -c --arg name "new_group_name" --arg comment "example comment" '$ARGS.named')
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" localhost:16216/api/forward/v3/web/groups
JSON_PAYLOAD=$(jq -n -c --arg name "new_group_name" --arg comment "example comment" '$ARGS.named')
curl -s -H"Authorization: Bearer $HUSARNET_JWT" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" https://api.beta.husarnet.com/v3/web/groups
Group name has to be at least 2 characters long and cannot exceed 100 characters. Whitespace (e.g. space character) is also not allowed. Best names are short and memorable.
Updating group information
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i group update <group name or id> --name <new name>
For any existing group owned by you, you can change:
- emoji, by passing
--emoji <new emoji>parameter - name, by passing
--name <new name>parameter - comment, by passing
--comment <new comment>parameter
Use PUT request.
JSON_PAYLOAD=$(jq -n -c --arg name "new_group_name" --arg comment "example comment" '$ARGS.named')
curl -s -X PUT -H"X-Husarnet-Secret: $HUSARNET_SECRET" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" localhost:16216/api/forward/v3/web/groups/<group id>
Use PUT request.
JSON_PAYLOAD=$(jq -n -c --arg name "new_group_name" --arg comment "example comment" '$ARGS.named')
curl -s -X PUT -H"Authorization: Bearer $HUSARNET_JWT" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" https://api.beta.husarnet.com/v3/web/groups/<group id>
Deleting a group
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i group delete <group name or id>
The CLI will ask for confirmation before sending the DELETE request.
Use DELETE request.
curl -s -X DELETE -H"X-Husarnet-Secret: $HUSARNET_SECRET" localhost:16216/api/forward/v3/web/groups/<group id>
Use DELETE request.
curl -s -X DELETE -H"Authorization: Bearer $HUSARNET_JWT" https://api.beta.husarnet.com/v3/web/groups/<group id>
Devices
Listing devices
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i device ls
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" localhost:16216/api/forward/v3/web/devices
curl -s -H"Authorization: Bearer $HUSARNET_JWT" https://api.beta.husarnet.com/v3/web/devices
Possible output:
{
"type": "success",
"errors": [],
"warnings": [],
"message": "OK",
"payload": [
{
"id": "14fe531e-c72e-45b3-b3f5-17ca2188a4f5",
"ip": "fc94:dede:eeee:dede:eeee:dede:eeee:dede",
"emoji": "🤖",
"hostname": "gnaarmok",
"userAgent": "Husarnet,Linux,AMD64,2.0.333",
"comment": "",
"aliases": null,
"status": "on",
"lastContact": "2025-11-17T14:43:49.246282Z"
},
{
"id": "c3ca3ded-02cd-4be3-b291-8a5576437fa0",
"ip": "fc94:dede:eeee:dede:eeee:dede:eeee:dede",
"emoji": "🤖",
"hostname": "macos-testing",
"userAgent": "Husarnet,MacOS,ARM64,2.0.330",
"comment": "",
"aliases": null,
"status": "on",
"lastContact": "2025-11-17T14:43:42.83495Z"
}
]
}
Viewing a device
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i device show <device uuid OR IPv6 addr OR hostname>
You can provide device UUID, IPv6 address or hostname as an argument here. The CLI will figure out the correct UUID to put into the request.
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" localhost:16216/api/forward/v3/web/devices/<device uuid>
curl -s -H"Authorization: Bearer $HUSARNET_JWT" https://api.beta.husarnet.com/v3/web/groups/<device uuid>
Example output:
{
"type": "success",
"errors": [],
"warnings": [],
"message": "OK",
"payload": {
"id": "14fe531e-c72e-45b3-b3f5-17ca2188a4f5",
"ip": "fc94:7e37:b5d5:4489:261c:3899:9845:8482",
"emoji": "🤖",
"hostname": "gnaarmok",
"userAgent": "Husarnet,Linux,AMD64,2.0.333",
"comment": "",
"aliases": null,
"status": "on",
"lastContact": "2025-11-17T15:06:52.958036Z"
}
}
Attaching a device to a group
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
Provide device identifier (UUID, IPv6 address or hostname) as first positional parameter, and group identifier (UUID or name) as second.
husarnet --json -i device attach [device] <group uuid OR name>
For example:
husarnet --json -i device attach gnaarmok robots
Omitting device identifier will attach the current device (the one where the command is run). The CLI will figure out the correct UUIDs to put into the request.
You need to provide groupId (uuid) and deviceIp (starting from fc94:) in the JSON payload.
JSON_PAYLOAD=$(jq -n -c --arg groupId "group_uuid_here" --arg deviceIp "ip here" '$ARGS.named')
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" localhost:16216/api/forward/v3/web/groups/attach-device
You need to provide groupId (uuid) and deviceIp (starting from fc94:) in the JSON payload.
JSON_PAYLOAD=$(jq -n -c --arg groupId "group_uuid_here" --arg deviceIp "ip here" '$ARGS.named')
curl -s -H"Authorization: Bearer $HUSARNET_JWT" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" https://api.beta.husarnet.com/v3/web/groups/attach-device
Detaching a device from a group
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
Provide device identifier (UUID, IPv6 address or hostname) as first positional parameter, and group identifier (UUID or name) as second.
husarnet --json -i device detach [device] <group uuid OR name>
For example:
husarnet --json -i device detach gnaarmok robots
Omitting device identifier will detach the current device (the one where the command is run). The CLI will figure out the correct UUIDs to put into the request.
You need to provide groupId (uuid) and deviceIp (starting from fc94:) in the JSON payload.
JSON_PAYLOAD=$(jq -n -c --arg groupId "group_uuid_here" --arg deviceIp "ip here" '$ARGS.named')
curl -s -H"X-Husarnet-Secret: $HUSARNET_SECRET" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" localhost:16216/api/forward/v3/web/groups/detach-device
You need to provide groupId (uuid) and deviceIp (starting from fc94:) in the JSON payload.
JSON_PAYLOAD=$(jq -n -c --arg groupId "group_uuid_here" --arg deviceIp "ip here" '$ARGS.named')
curl -s -H"Authorization: Bearer $HUSARNET_JWT" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" https://api.beta.husarnet.com/v3/web/groups/detach-device
Updating device information
- CLI
- Daemon-proxied (cURL)
- Direct with JWT (cURL)
husarnet --json -i device update <device uuid OR ip OR hostname> --hostname <new hostname>
For any existing device owned by you, you can change:
- emoji, by passing
--emoji <new emoji>parameter - hostname, by passing
--hostname <new name>parameter - comment, by passing
--comment <new comment>parameter
Use PUT request.
JSON_PAYLOAD=$(jq -n -c --arg hostname "new_hostname" --arg comment "example comment" '$ARGS.named')
curl -s -X PUT -H"X-Husarnet-Secret: $HUSARNET_SECRET" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" localhost:16216/api/forward/v3/web/devices/<device UUID>
Use PUT request.
JSON_PAYLOAD=$(jq -n -c --arg hostname "new_hostname" --arg comment "example comment" '$ARGS.named')
curl -s -X PUT -H"Authorization: Bearer $HUSARNET_JWT" -H"Content-Type: application/json" -d "$JSON_PAYLOAD" https://api.beta.husarnet.com/v3/web/devices/<device UUID>