Proxies

A proxy is one 4G dongle on one of your nodes, published on one public port of our cloud router. Its id is the number in the panel URL (/proxies/7).

The proxy object

{
  "id": 7,
  "label": "Shop A",
  "host": "152.67.6.160",
  "port": 30007,
  "pending_host": null,
  "pending_port": null,
  "switch_at": null,
  "status": "online",
  "enabled": true,
  "disabled_reason": null,
  "data_connection": "connected",
  "data_connection_reason": null,
  "current_ip": "100.64.1.2",
  "signal": {"network_type": "LTE", "rsrp": "-95dBm"},
  "fingerprint": "android",
  "auto_rotate_seconds": null,
  "sticky": false,
  "last_rotated_at": "2026-10-09T18:00:00+00:00",
  "rotation_url": "https://proxykite.com/r/<rotation_token>",
  "expires_at": null,
  "quota_bytes": null,
  "used_bytes": 123456,
  "node": {"id": 12, "hostname": "proxyserver2", "online": true, "name": "Rack A", "display_name": "Rack A",
           "country_code": "IN", "city": "Kolkata"},
  "users": [
    {"username": "u7abc", "password": "s3cret", "max_conn": 200, "enabled": true,
     "http": "http://u7abc:s3cret@152.67.6.160:30007",
     "socks5": "socks5://u7abc:s3cret@152.67.6.160:30007"}
  ],
  "whitelist": [{"id": 3, "cidr": "203.0.113.4/32", "note": "office"}],
  "ports": {"mode": "shared", "http_port": 30007, "socks5_port": 30007, "host": "152.67.6.160",
            "range": {"min": 30000, "max": 30999}},
  "site_rules": {"mode": "off", "count": 0},
  "limits": {"...": "..."},
  "traffic": {"...": "..."},
  "device": {"...": "..."}
}
FieldMeaning
idproxy id
labelyour name for it (null = none). Change with PATCH /proxies/{id}
host, portthe public endpoint; see Proxy formats. host is the cloud router your node is on: a hostname such as gw-in-bom-1.vpslake.com or an IP. Always read it from the API — do not hard-code it
pending_host, pending_port, switch_atset only while your node is scheduled to move to another cloud router: the new host (and port, normally unchanged) and when the switch happens. null otherwise. You also get an email and the proxy.address_changing webhook
statusonline, offline, pending_approval or over_limit
enabledfalse when the proxy refuses connections; disabled_reason says why
disabled_reasonnull, or one of the reasons below
data_connectionwhether the device has mobile data: connected, disconnected or unknown (device not online, or no reading in the last 10 minutes). status only says whether the box sees the device; a proxy can be online with disconnected data (e.g. HiLink connection status 902 on a 2G-only SIM, or a modem whose data bearer is down). The panel shows disconnected as a "No data" badge
data_connection_reasonwhy it is disconnected, e.g. "disconnected (902) · EDGE"; otherwise null
current_ipthe mobile IP the proxy exits from
country_codecountry of current_ip (ISO-2)
isp{"name", "asn", "as_name", "org", "country_code", "logo_url"} of the exit IP, or null. country_code and isp come from a cached lookup refreshed every minute or so — right after a rotation they still show the previous IP's values
signalradio details when the dongle reports them (network_type, operator, rsrp, rsrq, sinr, rssi, …); may be {}
fingerprintOS fingerprint profile (android, iphone, none)
auto_rotate_secondsauto-rotation interval, null = off. See Rotation
stickytrue pauses auto-rotation, keeping the current IP
last_rotated_atlast successful rotation
rotation_urlsecret rotation link
expires_atfor reseller sub-user assignments: when access ends (null = never)
quota_bytes, used_bytestraffic quota (null = unlimited) and traffic used
nodethe box the dongle is plugged into: id, hostname, online, name, display_name, country_code, city; see Nodes
usersproxy logins, with ready-to-use http and socks5 URLs
whitelistclient IPs/ranges allowed without a password; see Whitelist
portsport mode and the HTTP / SOCKS5 port numbers; see Ports
site_rules{"mode", "count"} of the proxy's website rules
traffictraffic-insights settings and status; see Traffic insights
simGET /proxies/{id} only, not for reseller sub-users; see SIM card and recharge date
limitsSMS and bandwidth limits with current usage; see SMS and bandwidth limits
devicewhat the device is and what it can do: type, model, capabilities, permanent uid; see Device type and capabilities

disabled_reason values: pending_approval (the node has auto-adopt off — approve the dongle under Nodes), admin_disabled, over_limit (more dongles than the licence allows), license_suspended, subscription_expired (the licence was not renewed: paid-until date + grace days have passed — it comes back by itself after renewal), owner_suspended, unpaid, assignee_suspended, expired, over_quota, bandwidth_limit (a day/week/month bandwidth limit is used up — the proxy starts again when that period resets), no_address (the dongle has no IP on the box yet).

List proxies

GET /proxies

Ability: read · Every proxy your login can see, ordered by id (up to 2000). Reseller sub-users see only the proxies assigned to them.

curl
Python
Node.js
PHP
curl 'https://proxykite.com/api/v1/proxies' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'

Response 200: {"data": [<proxy>, ...]}

Get one proxy

GET /proxies/{id}

Ability: read

curl
Python
Node.js
PHP
curl 'https://proxykite.com/api/v1/proxies/7' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'

Response 200: {"data": <proxy>} · 404 not_found if the proxy does not exist or is not yours.

Rename a proxy

PATCH /proxies/{id}

Ability: manage · Who: account owner or team admin (sub-users and viewers get 403 forbidden).

Body fieldType
labelstring ≤ 100 chars, or null / ""required — null or "" clears the label
curl
Python
Node.js
PHP
curl -X PATCH 'https://proxykite.com/api/v1/proxies/7' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"label":"Shop A"}'

Response 200: {"data": <proxy>} (the updated proxy).

SIM card and recharge date

PATCH /proxies/{id}

Ability: manage · Who: account owner or team admin. The SIM details of a dongle: phone number, operator, plan note and the next recharge date. We remind you (see Alerts) about 09:00 in your timezone remind_days_before days before, on the day, and daily for a week while overdue. GET /proxies/{id} returns the same sim object (not for reseller sub-users). These details belong to the SIM card: when the device reports its SIM (ICCID), a SIM moved to another dongle takes its number, recharge date and SMS limits along. Read-only extras: id, identified (the SIM's ICCID is known), iccid_last4, sms_limits {day, week, month}. Send only the keys you change; null or "" clears one. sim may be sent alone or together with label / other fields.

sim field
phoneinternational format, + and 7–15 digits (spaces/dashes are removed)
operator≤ 60 chars. Read-only operator_detected = the exit IP's ISP, a hint
plan≤ 200 chars, free text
next_recharge_dateYYYY-MM-DD
remind_days_before0–60, default 3
curl
Python
Node.js
PHP
curl -X PATCH 'https://proxykite.com/api/v1/proxies/7' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"sim":{"phone":"+919800000000","operator":"Jio","next_recharge_date":"2026-11-01","remind_days_before":3}}'

Response 200: {"data": <proxy with "sim">}:

"sim": {"phone": "+919800000000", "operator": "Jio", "operator_detected": "Reliance Jio Infocomm",
        "plan": null, "next_recharge_date": "2026-11-01", "remind_days_before": 3, "days_left": 22}

days_left is counted in the owner's timezone; negative = overdue. Errors name the fields sim_phone, sim_recharge_date, … in fields.

SMS and bandwidth limits

GET /proxies/{id}/limits · PATCH /proxies/{id}

Ability: read to see them (also the limits object in every proxy), manage to change them · Who changes: account owner or team admin (reseller sub-users and viewers see them read-only).

Each proxy can have an SMS send limit and a bandwidth limit per day, week (Monday–Sunday) and month — each optional. Periods are calendar periods in the account's timezone (timezone in the answer).

  • SMS: every SMS the dongle accepts (panel or POST /proxies/{id}/sms) counts. When a limit is used up, sending is refused with 429 sms_limit_reached until that period resets.
  • Bandwidth: traffic in + out of all proxy logins, checked about once a minute. At 80 % you get a bandwidth_warning alert, at 100 % the proxy stops (enabled:false, disabled_reason:"bandwidth_limit") and you get bandwidth_limit_reached; it starts again by itself when the period resets. Raising/removing the limit or reset_bandwidth starts it at once.

PATCH body — send only what you change; null or 0 removes a limit:

limits field
sms.day, sms.week, sms.monthmax SMS per period (0–1,000,000)
bandwidth_mb.day, .week, .monthmax traffic per period in MB (1 GB = 1024 MB)
reset_bandwidthtrue = count bandwidth from zero again in the current day/week/month (unblocks)
curl
Python
Node.js
PHP
curl -X PATCH 'https://proxykite.com/api/v1/proxies/7' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"limits":{"sms":{"day":50,"month":1000},"bandwidth_mb":{"day":5120,"month":null}}}'

Response 200: {"data": <proxy>}. The limits object (also from GET /proxies/{id}/limits as {"data": …}):

{"timezone": "Asia/Kolkata",
 "sms": {"day": {"limit": 50, "used": 12, "resets_at": "2026-10-10T18:30:00+00:00"},
         "week": {"limit": null, "used": 40, "resets_at": "2026-10-11T18:30:00+00:00"},
         "month": {"limit": 1000, "used": 210, "resets_at": "2026-10-31T18:30:00+00:00"}},
 "bandwidth": {"day": {"limit_bytes": 5368709120, "used_bytes": 4400000000, "percent": 82, "resets_at": "2026-10-10T18:30:00+00:00"},
               "week": {"limit_bytes": null, "used_bytes": 9100000000, "percent": null, "resets_at": "2026-10-11T18:30:00+00:00"},
               "month": {"limit_bytes": null, "used_bytes": 30500000000, "percent": null, "resets_at": "2026-10-31T18:30:00+00:00"}},
 "blocked": false, "blocked_reason": null, "blocked_period": null, "blocked_until": null}

blocked: true (with blocked_period and blocked_until) while a bandwidth limit has stopped the proxy. Usage is counted in hourly steps: with a half-hour timezone (e.g. India) the hour that straddles midnight counts to the previous period.

curl
Python
Node.js
PHP
curl 'https://proxykite.com/api/v1/proxies/7/limits' \
  -H "Authorization: Bearer $HYP_TOKEN" \
  -H 'Accept: application/json'

Device type and capabilities

Every proxy object carries a device object. Your own logins (not reseller sub-users) also get device.identity.

"device": {
  "uid": "01k7c2y9s8m3v5q1x0h4f6t2wb",
  "type": "hilink",
  "type_label": "Huawei HiLink dongle",
  "reported": true,
  "model": "E3372h-320",
  "firmware": "22.333.01.00.00",
  "driver_version": "1.0.0",
  "state": "ok",
  "control_via": "panel",
  "identity_state": "confirmed",
  "capabilities": {
    "egress": {"s": "yes", "kind": "netdev"},
    "rotate.netmode": {"s": "yes"},
    "sms.send": {"s": "yes"},
    "ussd": {"s": "setup", "hint": "Install ModemManager: sudo hostyourproxy setup modem"},
    "web_ui": {"s": "no"}
  },
  "rotate_methods": ["netmode", "reconnect", "reboot"],
  "identity": {"imei_last4": "0123", "moved_from_node_id": null, "moved_at": null,
               "conflict_with_proxy_id": null, "restorable_from_proxy_id": null}
}
FieldMeaning
uidpermanent id of the device; stays the same when the device moves to another USB port or another of your nodes
typehilink (Huawei HiLink dongle), mm (USB modem), android (phone), generic (plain network interface, no device control)
reportedfalse = the node runs an older agent and the type is assumed
capabilitieseach capability → s: yes (works now), setup (possible; hint says what to do) or no
rotate_methodsrotation methods that work now, in the order the panel tries them
identity_stateconfirmed (hardware ID known — settings follow the device), weak (no ID — settings follow the USB port), identifying, conflict (two proxies report one ID; choose in the panel)
identityowner/team only: last 4 digits of the IMEI, where it moved from, conflict and restore pointers

Capability names: egress, rotate.netmode, rotate.reconnect, rotate.airplane, rotate.reboot, rotate.link_bounce, status.signal, sms.read, sms.send, sms.delete, ussd, device.reboot, web_ui, lan.settings, netmode.set, identity.imei, identity.iccid, identity.imsi, identity.device_key, data_connect (the box brings the device's data connection up itself, with your APN). Show only what is yes. Asking for something the device cannot do answers 409 unsupported with the capability that is missing (rotation, rotation links, sending SMS; the SMS list and interface endpoints only when the device has no such thing at all; the interface endpoints when egress.kind is app).

Delete and restore

Deleting a proxy frees its public port at once and stops it. Its logins, whitelist, label and rotation link are kept for 7 days: restore them here or in the panel (Nodes → Interfaces → Recently deleted). When the same device is plugged in again within those days, it comes back as a new proxy and the panel offers to restore the old settings. Only the account owner or a team admin can delete or restore; reseller sub-users cannot (nor list deleted proxies). A live proxy whose interface shows warnings.possible_duplicate_of is a likely candidate for deleting — nothing is deleted automatically.

DELETE /proxies/{id}manage → {"ok": true, "data": {"id", "label", "node_id", "device_uid", "device_type", "port", "deleted_at", "restorable_until"}}
GET /proxies/deletedread → {"data": [ …same objects… ]} (port = the port it had)
POST /proxies/{id}/restoremanage → {"ok": true, "data": <proxy>}; the old port comes back when it is still free. If the device is already back as a new proxy, that new proxy is replaced by the restored one. 404 after 7 days
curl -X DELETE 'https://proxykite.com/api/v1/proxies/7' -H "Authorization: Bearer $HYP_TOKEN" -H 'Accept: application/json'
curl -X POST 'https://proxykite.com/api/v1/proxies/7/restore' -H "Authorization: Bearer $HYP_TOKEN" -H 'Accept: application/json'