#Nodes
A node is your Linux box running the ProxyKite agent, with the dongles plugged into it. Its id is in the panel
URL (/nodes/12) and in each proxy's node.id. Not available to reseller sub-users (GET /nodes answers an
empty list, the other endpoints 404 not_found).
#The node object
{"id": 12, "name": "Rack A", "display_name": "Rack A", "hostname": "proxyserver2", "online": true,
"tunnel_connected": true, "last_seen_at": "2026-10-10T08:00:00+00:00", "agent_version": "1.2.0",
"os": "Debian GNU/Linux 12", "arch": "arm64", "uptime_s": 86400,
"public_ip": "106.192.92.83",
"location": {"country_code": "IN", "country": "India", "city": "Kolkata", "source": "auto"},
"isp": {"name": "Airtel", "asn": 9498, "as_name": "BHARTI-AIRTEL", "org": "Bharti Airtel Ltd", "country_code": "IN",
"logo_url": "https://proxykite.com/isp-logos/airtel.png"},
"dongles": 2,
"uplink": {"mode": "auto", "state": "system", "text": "Ethernet / default route"}}| Field | Meaning |
|---|---|
name | your name for the box (null = none) |
display_name | name, or the hostname when no name is set |
hostname | the box's own hostname |
online, tunnel_connected, last_seen_at | whether the box is up and its tunnel to the cloud router is connected; last heartbeat |
agent_version, os, arch, uptime_s | what the box reports about itself |
public_ip | the box's public IP |
location | country_code, country, city and source: auto = from the box's public IP, manual = set by you |
isp | {"name", "asn", "as_name", "org", "country_code", "logo_url"} of the box's connection |
dongles | number of dongles on the box |
uplink | tunnel uplink: your mode and the current state / text — see Tunnel uplink |
#List nodes
GET /nodesAbility: read · Your boxes. Reseller sub-users get an empty list.
curl 'https://proxykite.com/api/v1/nodes' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/nodes",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())const res = await fetch('https://proxykite.com/api/v1/nodes', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());<?php
$ch = curl_init('https://proxykite.com/api/v1/nodes');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));Response 200: {"data": [<node>, ...]}
#Get one node
GET /nodes/{id}Ability: read
curl 'https://proxykite.com/api/v1/nodes/12' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/nodes/12",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())const res = await fetch('https://proxykite.com/api/v1/nodes/12', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());<?php
$ch = curl_init('https://proxykite.com/api/v1/nodes/12');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));Response 200: {"data": <node>}
#Rename or set the location
PATCH /nodes/{id}Ability: manage · Who: owner or team admin.
| Body field | Type | |
|---|---|---|
name | string ≤ 64 chars, or null | optional — null or "" = use the hostname |
country_code | ISO-2, e.g. IN | optional — switches the location to manual |
city | string or null | optional — switches the location to manual |
location_source | auto | manual | optional — auto goes back to the location of the box's public IP |
curl -X PATCH 'https://proxykite.com/api/v1/nodes/12' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"name":"Rack A","country_code":"IN","city":"Kolkata"}'import os
import requests
r = requests.patch(
"https://proxykite.com/api/v1/nodes/12",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
json={"name": "Rack A", "country_code": "IN", "city": "Kolkata"},
timeout=30,
)
print(r.status_code, r.json())const res = await fetch('https://proxykite.com/api/v1/nodes/12', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({"name":"Rack A","country_code":"IN","city":"Kolkata"}),
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());<?php
$ch = curl_init('https://proxykite.com/api/v1/nodes/12');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{"name":"Rack A","country_code":"IN","city":"Kolkata"}',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));To go back to the automatic location:
curl -X PATCH 'https://proxykite.com/api/v1/nodes/12' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"location_source":"auto"}'import os
import requests
r = requests.patch(
"https://proxykite.com/api/v1/nodes/12",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
json={"location_source": "auto"},
timeout=30,
)
print(r.status_code, r.json())const res = await fetch('https://proxykite.com/api/v1/nodes/12', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({"location_source":"auto"}),
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());<?php
$ch = curl_init('https://proxykite.com/api/v1/nodes/12');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{"location_source":"auto"}',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));Response 200: {"data": <node>}
#Interfaces of a node
GET /nodes/{id}/interfacesAbility: read
Everything the box reported about its network interfaces: the dongles (as interface objects), its other interfaces, and box commands that are still pending.
curl 'https://proxykite.com/api/v1/nodes/12/interfaces' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'import os
import requests
r = requests.get(
"https://proxykite.com/api/v1/nodes/12/interfaces",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())const res = await fetch('https://proxykite.com/api/v1/nodes/12/interfaces', {
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());<?php
$ch = curl_init('https://proxykite.com/api/v1/nodes/12/interfaces');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));Response 200
{"data": {
"node_id": 12,
"auto_adopt": true,
"ignored_macs": [],
"adopted_macs": [],
"reported_at": "2026-10-09T18:00:00+00:00",
"dongles": [{"proxy_id": 7, "iface": "enx0c5b8f279a64", "...": "..."}],
"other_interfaces": [{"iface": "eth0", "mac": "dc:a6:32:00:00:01", "...": "..."}],
"pending_actions": [{"id": 42, "type": "rescan", "mac": null, "hw_key": null, "status": "pending", "error": null,
"created_at": "2026-10-09T18:00:00+00:00"}]
}}| Field | Meaning |
|---|---|
auto_adopt | true: new dongles become proxies automatically; false: they wait as pending_approval |
ignored_macs | interfaces you told the panel to ignore |
adopted_macs | non-Huawei interfaces you adopted as proxies |
other_interfaces | the box's interfaces that are not proxies (as reported by the agent) |
pending_actions | queued box commands (rescan, reset_iface, …) not yet picked up |
#Rescan
POST /nodes/{id}/rescanAbility: manage · Who: owner or team admin.
Asks the box to look for new or removed dongles now, instead of waiting for its next scan.
curl -X POST 'https://proxykite.com/api/v1/nodes/12/rescan' \
-H "Authorization: Bearer $HYP_TOKEN" \
-H 'Accept: application/json'import os
import requests
r = requests.post(
"https://proxykite.com/api/v1/nodes/12/rescan",
headers={"Authorization": f"Bearer {os.environ['HYP_TOKEN']}", "Accept": "application/json"},
timeout=30,
)
print(r.status_code, r.json())const res = await fetch('https://proxykite.com/api/v1/nodes/12/rescan', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HYP_TOKEN}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());<?php
$ch = curl_init('https://proxykite.com/api/v1/nodes/12/rescan');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HYP_TOKEN'),
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
var_dump($status, json_decode($body, true));Response 202
{"data": {"id": 42, "type": "rescan", "mac": null, "hw_key": null, "status": "pending", "error": null,
"created_at": "2026-10-09T18:00:00+00:00"}}