curl --request GET \
--url https://api.example.com/v1/panel/reports/trafficimport requests
url = "https://api.example.com/v1/panel/reports/traffic"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/panel/reports/traffic', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/v1/panel/reports/traffic",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/panel/reports/traffic"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v1/panel/reports/traffic")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/panel/reports/traffic")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"nodes": [
{
"name": "<string>",
"connected": true,
"disabled": true,
"usedBytes": 123,
"limitBytes": 123,
"countryCode": "<string>",
"usedShare": 123,
"usersOnline": 123
}
],
"nodesReported": true,
"consumers": [
{
"remnawaveId": 123,
"username": "<string>",
"usedBytes": 123,
"lifetimeBytes": 123,
"limitBytes": 123,
"customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "<string>",
"status": "<string>"
}
],
"scanned": 123,
"total": 123,
"nodesDetail": "nodes_unsupported"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"request_id": "<string>"
}Get v1panelreportstraffic
Requires customers.read. Node saturation and the heaviest users, read live from Remnawave on every request.
Omniflow stores none of it. Remnawave is authoritative for traffic, nodes, and connections, and this repository has no table for a node or for a byte a customer used — keeping one would be the first step towards Omniflow having an opinion about traffic. What Omniflow adds is the join: a Remnawave user identifier resolved to the customer who holds it.
nodesReported is false when the panel does not expose a node listing or could not be reached, and nodesDetail says which. An empty node list and no node data look identical on a screen and mean opposite things.
The consumer ranking pages the panel’s user list and stops after ten pages. scanned and total say how far it got, so a truncated ranking is never presented as a complete one.
curl --request GET \
--url https://api.example.com/v1/panel/reports/trafficimport requests
url = "https://api.example.com/v1/panel/reports/traffic"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v1/panel/reports/traffic', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/v1/panel/reports/traffic",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/panel/reports/traffic"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v1/panel/reports/traffic")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/panel/reports/traffic")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"nodes": [
{
"name": "<string>",
"connected": true,
"disabled": true,
"usedBytes": 123,
"limitBytes": 123,
"countryCode": "<string>",
"usedShare": 123,
"usersOnline": 123
}
],
"nodesReported": true,
"consumers": [
{
"remnawaveId": 123,
"username": "<string>",
"usedBytes": 123,
"lifetimeBytes": 123,
"limitBytes": 123,
"customerId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "<string>",
"status": "<string>"
}
],
"scanned": 123,
"total": 123,
"nodesDetail": "nodes_unsupported"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"request_id": "<string>"
}Response
Traffic report
Show child attributes
Show child attributes
False when the panel did not answer. An empty list means neither thing.
Show child attributes
Show child attributes
How many users the ranking covers.
How many the panel reports having.
nodes_unsupported, nodes_unavailable, remnawave_not_configured