nullroute Docs
On this page

NullRoute docs

Proxy gateway and tools API

One endpoint for residential, datacenter and mobile exits. The username picks the exit, the password is your API key.

Host
nullroute.176-97-210-16.sslip.io
Port
32424
Protocols
HTTP, HTTPS, SOCKS5, SOCKS4
Login
res-us : op-… or sk-…

Port 32443 is the same gateway inside TLS. The raw IP 176.97.210.16 also works on plain port 32424, but not for TLS: the certificate is issued for the hostname only.

По-русски

Быстрый старт

  1. Ключ. Зарегистрируйтесь и скопируйте ключ op-… в Dashboard → Settings. Для клиентов и сотрудников делайте отдельные ключи sk-… в API keys.

  2. Подключение. Хост nullroute.176-97-210-16.sslip.io, порт 32424 (то же в TLS — 32443). Протокол HTTP или SOCKS5 — порт один и тот же.

  3. Логин и пароль. Логин — какой IP нужен (res-us, dc-de, mob-gb), пароль — ваш ключ.

  4. Проверка. Должен вернуться IP из нужной страны:

    curl
    curl -x "http://res-us:op-ВАШ-КЛЮЧ@nullroute.176-97-210-16.sslip.io:32424" https://api.ipify.org
НужноЛогин
Новый IP на каждое соединениеres-us
Один IP надолго (сессия)res-us-sid-4821
Городres-us-city-new_york
Штат (США)res-us-st-texas или res-us-st-tx
ZIP (США)res-us-zip-10001
ОСres-us-os-windows
Несколько фильтровres-us-st-texas-os-windows
Провайдер (ASN)res-us-asn-7922
Любая странаres-any
  • Проверенные фильтры. -st-<штат> (res-us-st-texas или res-us-st-tx), -city-<город> (res-us-city-new_york), -zip-<5 цифр> — только США (res-us-zip-10001), -asn-<номер> (res-us-asn-7922), -os-<windows|android|linux|macos> (res-us-os-windows). Фильтры можно совмещать в одном логине: res-us-st-texas-os-windows.
  • Проверка до выдачи. Шлюз сверяет фильтр с выходом до передачи трафика. Если подходящего выхода нет, вернётся 502 no exit matching filter — списания не будет. ZIP проверяется по радиусу: выход геолоцирован не дальше 25 км от центра индекса, поэтому может оказаться в соседнем ZIP; точный адрес проверяйте через /api/exit-ip. Город тоже привязан к геолокации выхода и покрывает агломерацию (до 30 км): ждите город или его пригороды, а не адрес.
  • Несовместимо с -sid-. Липкую сессию и проверенные фильтры в одном логине не совместить: шлюз ответит 400 sid cannot be combined with geo filters. Выберите что-то одно.

Шифрованное соединение (TLS)

Порт 32443 — тот же шлюз, но клиент сначала поднимает TLS. Логин и пароль те же, меняются только схема и порт. Подключайтесь по имени хоста: сертификат выпущен для nullroute.176-97-210-16.sslip.io, по IP проверка сертификата не пройдёт.

curl
curl --proxy https://nullroute.176-97-210-16.sslip.io:32443 --proxy-user "res-us:op-ВАШ-КЛЮЧ" https://api.ipify.org

Для антидетекта и браузерных расширений строка такая: nullroute.176-97-210-16.sslip.io:32424:res-us-sid-4821:op-ВАШ-КЛЮЧ. Сессия держит один IP; если он умер, NullRoute сам переведёт её на новый. Соединение без трафика закрывается через 3 минуты. Ошибка 407 — ключ неверный, истёк или кончился лимит; 502 — выход не смог достучаться до сайта, повторите запрос.

Start

Quickstart

  1. Get your API key. Create an account, then copy the master key (op-…) from Dashboard → Settings. Keep it in an environment variable, not in source code.

    shell
    export NULLROUTE_KEY="op-your-key"
  2. Build the proxy URL. Username = the exit you want, password = the key.

    format
    http://<username>:<api-key>@nullroute.176-97-210-16.sslip.io:32424
  3. Send a request through a residential US exit and check the IP it left from.

    curl
    curl -x "http://res-us:$NULLROUTE_KEY@nullroute.176-97-210-16.sslip.io:32424" \
      "https://api.ipify.org?format=json"
    
    # {"ip":"203.0.113.24"}

Proxy

Endpoint and login

Every protocol uses the same host and port; the gateway detects the protocol from the first byte. Port 32443 carries the same four protocols inside TLS.

ProtocolProxy URLNotes
HTTP / HTTPShttp://res-us:KEY@nullroute.176-97-210-16.sslip.io:32424HTTPS sites go through CONNECT, so TLS stays end-to-end. The proxy URL itself is always http://.
SOCKS5socks5h://res-us:KEY@nullroute.176-97-210-16.sslip.io:32424Username/password auth only. socks5h resolves DNS on the exit. TCP only, no UDP.
SOCKS4 / 4asocks4a://res-us%3AKEY@nullroute.176-97-210-16.sslip.io:32424
socks4a://KEY@nullroute.176-97-210-16.sslip.io:32424
SOCKS4 has no password field, so the key must travel inside the user id: percent-encode the colon (res-us%3AKEY) or send the key alone. The plain res-us:KEY@ form does not work in curl — it splits userinfo at the colon and the gateway sees only res-us.

Encrypted connection (TLS)

Port 32443 speaks HTTP, HTTPS CONNECT, SOCKS4/4a and SOCKS5 inside TLS. The login is the same; only the proxy scheme and port change. Connect by hostname, not by IP: the certificate is issued for nullroute.176-97-210-16.sslip.io, so a client that dials the raw address fails certificate validation.

curl
# https:// scheme = TLS to the gateway first, then the normal request
curl --proxy https://nullroute.176-97-210-16.sslip.io:32443 --proxy-user "res-us:$NULLROUTE_KEY" https://api.ipify.org

Credentials

UsernamePasswordResult
res-usop-… or sk-…Standard form. Username selects the exit.
op-… or sk-…emptyRotating residential exit in a random country — the same as res-any, not US. For tools that only have one login field.
res-usanythingOnly from an allowlisted IP. No key needed.

op- is your account's master key. sk- keys are sub-keys with their own limits; give those to teammates, scripts and clients.

Proxy

Targeting

The username is <type>-<country>, then any of the verified filters: -st-, -city-, -zip-, -asn-, -os-. A sticky session (-sid-) replaces the filters.

ParameterFormatExampleNotes
Exit typeres · dc · mobdc-usResidential $0.60/GB, datacenter $0.20/GB, mobile $1.00/GB.
Country<type>-<cc>res-deISO 3166 two-letter code, lowercase. any picks a random country.
State<type>-<cc>-st-<state>res-us-st-texas or res-us-st-txUS states. Full name or two-letter code, lowercase.
City<type>-<cc>-city-<city>res-us-city-new_yorkCity in lowercase, spaces become underscores. Matched on the exit's geolocation, which is metro-wide: expect the city or its suburbs, not a street-level address.
ZIP<type>-<cc>-zip-<zip>res-us-zip-100015 digits, US only. Matched by distance: the exit is geolocated within 25 km of the ZIP's centre, so it may sit in a neighbouring ZIP. Confirm with /api/exit-ip if the exact ZIP matters.
ASN<type>-<cc>-asn-<n>res-us-asn-7922One network only, e.g. AS7922 (Comcast). Digits, no AS prefix.
OS<type>-<cc>-os-<os>res-us-os-windowswindows, android, linux or macos.
Combinedfilters joined in one usernameres-us-st-texas-os-windowsEvery filter must match the same exit.
Session<type>-<cc>-sid-<id>res-us-sid-4821Same id keeps the same IP. Letters and digits. Can't be combined with the filters above. See sessions.
Smart retrysr_ prefixsr_res-usRetries blocked plain-HTTP responses. See smart retry.
examples
res-us                        # residential, United States, new IP per connection
dc-de                         # datacenter, Germany
mob-gb                        # mobile carrier IP, United Kingdom
res-any                       # residential, random country
res-us-city-chicago           # residential, Chicago
res-us-st-texas-os-windows    # residential, Texas, Windows exits
res-us-zip-10001              # residential, US ZIP 10001
res-us-asn-7922               # residential, AS7922 only
res-us-os-android             # residential, Android exits
res-us-sid-4821               # sticky: same IP while you reuse sid 4821
sr_res-us                     # smart retry on blocked responses
  • Can I combine filters? Yes: res-us-st-texas-os-windows, res-us-city-new_york-asn-7922. Every filter in the username must match the same exit.
  • What if nothing matches? The gateway verifies the filter against the exit before it hands traffic over. With no matching exit the connection gets 502 no exit matching filter and nothing is charged.
  • Filters and sticky sessions? Not together. -sid- pins one exit, so a username can have either filters or a session id.

In the tools API, where city, ASN and session are separate fields, precedence is city > ASN > session: if you send several, only the first one applies.

Proxy

Sessions

ModeUsernameBehaviour
Rotatingres-usEvery new connection gets a new exit IP. Requests on one keep-alive connection or tunnel keep its IP.
Stickyres-us-sid-4821Every connection with the same id uses the same exit IP for as long as that exit stays online.
  • New IP: change the id, e.g. res-us-sid-4822. Use random ids (8+ digits) so parallel workers don't share an exit by accident.
  • Self-healing: if a sticky exit dies (two failed connects in a row, or a tunnel that drops before any data), NullRoute moves the session to a new IP. The id keeps that new IP afterwards, so your session stays stable instead of failing.
  • Private ids: ids are scoped to your account. Your sid-1 and another customer's sid-1 are different exits.
  • Idle timeout: a connection with no traffic in either direction for 3 minutes is closed. A single connection lives at most 24 hours. Reconnecting with the same id gets the same IP.
  • Header instead of username: HTTP clients can send X-Session-Id: 4821. With curl and HTTPS sites use --proxy-header "X-Session-Id: 4821".

Proxy

Code examples

Replace op-your-key or $NULLROUTE_KEY with your key. Each tab is copy-paste ready.

# HTTP proxy
curl -x "http://res-us:$NULLROUTE_KEY@nullroute.176-97-210-16.sslip.io:32424" https://api.ipify.org

# SOCKS5, DNS resolved on the exit
curl -x "socks5h://res-us:$NULLROUTE_KEY@nullroute.176-97-210-16.sslip.io:32424" https://api.ipify.org

# Sticky session in Germany
curl -x "http://res-de-sid-4821:$NULLROUTE_KEY@nullroute.176-97-210-16.sslip.io:32424" https://api.ipify.org

For a browser profile use a sticky username (-sid-), one id per profile, so the IP doesn't change between page loads.

Proxy

Smart retry

Prefix the username with sr_. When a response looks blocked, NullRoute sends the request again from a fresh exit in the same country, up to 3 attempts, and returns the first clean response.

  • Counts as blocked: Cloudflare challenge (cf-mitigated: challenge, or 503 from Cloudflare), DataDome block, captcha or "access denied" pages, HTTP 429.
  • Costs $0.001 per request that needed a retry and then succeeded. First-try successes cost bandwidth only.
  • Works for plain http:// requests through the HTTP proxy. HTTPS tunnels and SOCKS are end-to-end encrypted, so the gateway can't read the response. For HTTPS targets, use POST /api/fetch, where retry is on by default.
curl
curl -x "http://sr_res-us:$NULLROUTE_KEY@nullroute.176-97-210-16.sslip.io:32424" http://example.com/

Proxy

Keys and limits

Sub-keys

Create sk-… keys in Dashboard → API keys and use them anywhere the master key works: as the proxy password or as the API bearer token. Disable or delete one without touching the master key. Each sub-key can have:

LimitWhat happens
Expiry dateStops working at the end of that day, UTC.
Traffic cap (GB)New connections are refused once the key has used its GB.
Spend cap ($)Same, by money spent instead of traffic.
Exit types and countriesUsernames outside the list are refused, e.g. mob-gb on a key limited to res.
Speed cap (Mbps)Shared by all connections of the key. Set on keys issued by NullRoute.

Limits are checked when a connection opens; a connection already running finishes. The account's daily spend limit (in API keys) applies to every key.

IP allowlist

Connections from an allowlisted IP or CIDR range don't need a key. Send only the exit as the username:

curl
# from an allowlisted server
curl -x http://res-us@nullroute.176-97-210-16.sslip.io:32424 https://api.ipify.org

IPv4 or IPv6, single address or CIDR, up to 50 entries. SOCKS5 still needs a username and a password field: send res-us and any non-key password. Allowlisted traffic bills the master balance.

Proxy

Troubleshooting

You seeCauseWhat to do
407 Proxy Authentication Required (HTTP), or the connection closes right after login (SOCKS)Key missing, mistyped, disabled or expired; sub-key out of traffic or spend; no balance; daily spend limit hit; exit type or country not allowed for the sub-key. Over HTTP the reason is in the response body and the X-Proxy-Error header (invalid_credentials, insufficient_balance, quota_exceeded, key_expired, exit_not_allowed…).Check the key in API keys, top up in Billing, or raise the cap. The key goes in the password, not the username.
400 unknown exit type / unknown country codeThe username doesn't start with res, dc or mob, or the country isn't an ISO code.Use e.g. res-us, dc-de, mob-gb or res-any.
502 Bad Gateway, or SOCKS "general failure"No exit could reach the site after several attempts: site down, port closed, or no IPs left for that city / ASN.Retry. If it repeats, widen targeting (drop the filter, try another country).
502 no exit matching filterA verified filter (-st-, -city-, -zip-, -asn-, -os-) has no matching exit right now.Widen or drop the filter, or retry later. The request is not charged.
502 no exit available for this location right now (X-Proxy-Error: no_exit_for_location), or an HTTPS tunnel that closes right after the handshakeThe network has no exits in that country at the moment. Small territories are often not covered. After one refusal the gateway answers this for 10 minutes without trying again.Pick a nearby country or another network type. The request is not charged.
curl: (97) Can't complete SOCKS4 connection (reply 91)The SOCKS4 user id was cut at the colon: socks4a://res-us:KEY@… and --proxy-user "res-us:KEY" both send only res-us, because SOCKS4 has no password field.Percent-encode the colon in the URL (socks4a://res-us%3AKEY@…) or send the key alone (socks4a://KEY@…).
Requests go to the US although you wanted another countryThe username has no country: an empty username (http://:KEY@…, http://KEY:@…), the key alone, or a bare res / dc / mob defaults to <type>-us.Put the exit first: http://res-de:KEY@…, or res-any for a random country. An empty password with a real username (res-us:) is rejected with 407.
Username with -sid- and a filter is refusedSticky sessions and verified filters can't be combined in one username. The gateway answers 400 with the body sid cannot be combined with geo filters.Send either the filters or -sid-<id>.
403 Forbidden, or SOCKS "not allowed"The destination host or port is blocked by network policy (e.g. SMTP).Not available through NullRoute.
IP changes on every requestRotating username, or your client opens a new connection per request.Add -sid-<id> to the username.
Sticky IP changedThe exit went offline and the session was moved to a new IP.Expected. Check the current IP with /api/exit-ip if you need it.
Connection drops after a pause3-minute idle timeout (or the 24-hour connection limit).Reconnect; same sid means same IP.
Your own IP shows on Windowscurl in PowerShell is Invoke-WebRequest, or -x was left out.Use curl.exe -x ….

Tools API

Authentication

The tools API runs checks through NullRoute exits and bills your balance per call. Send your key as a bearer token. Master keys (op-…) and sub-keys (sk-…) both work; sub-key scope rules apply.

header
Authorization: Bearer op-your-key
  • Base URL: https://nullroute.176-97-210-16.sslip.io. JSON in, JSON out.
  • X-API-Key: op-your-key also works. A key query or body field is accepted but ends up in logs, so prefer the header.
  • Every successful response has a charged field: what the call cost in USD.
  • Exit targeting fields (type, country, city, asn, session) mirror the username parameters. Defaults: res, us.

Tools API

Endpoints

POST

/api/fetch

$0.001 + bandwidth

Fetches a URL through an exit and returns status, headers, body and timings. Retries blocked responses on a new exit by default.

FieldTypeDescription
urlrequiredstringhttp or https URL.
methodstringDefault GET.
headersobjectRequest headers, up to 32.
bodystringRequest body.
type, country, city, asn, sessionstringExit targeting. Default res, us.
retrybooleanDefault true. Up to 3 attempts on fresh sticky exits; +$0.001 when a retry was needed.
follow_redirectsbooleanDefault true, up to 10 hops.
timeout_msnumberDefault 30000, range 1000–120000.
request
curl https://nullroute.176-97-210-16.sslip.io/api/fetch \
  -H "Authorization: Bearer $NULLROUTE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","country":"de"}'
response
{
  "status": 200,
  "final_url": "https://example.com/",
  "headers": { "content-type": "text/html", "server": "cloudflare" },
  "body": "<!doctype html>…",
  "body_base64": null,
  "bytes": 1712,
  "truncated": false,
  "ttfb_ms": 412,
  "total_ms": 468,
  "attempts": 1,
  "blocked": null,
  "exit_type": "res",
  "country": "de",
  "charged": 0.0010005
}

Binary bodies come back in body_base64. Bodies over 8 MB are cut and flagged truncated. If every attempt is blocked you get the last response with blocked set (challenge, captcha, blocked, rate_limited) and pay bandwidth only.

POST

/api/geo-check

$0.002 / country + bandwidth

Loads one URL from up to 15 countries in parallel and tells you whether they all got the same content. Use it to spot geo-blocks and localized pages.

FieldTypeDescription
urlrequiredstringhttp or https URL.
countriesrequiredstring[]1–15 country codes, e.g. ["us","de","jp"].
typestringExit type for every country. Default res.
methodstringDefault GET.
timeout_msnumberPer country. Default 20000, max 60000.
request
curl https://nullroute.176-97-210-16.sslip.io/api/geo-check \
  -H "Authorization: Bearer $NULLROUTE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","countries":["us","de","jp"]}'
response
{
  "url": "https://example.com",
  "exit_type": "res",
  "results": [
    { "country": "us", "ok": true, "status": 200, "ttfb_ms": 380, "total_ms": 402,
      "final_url": "https://example.com/", "redirected": false, "title": "Example Domain",
      "content_length": 1256, "content_hash": "84238dfc8092e5d9c0dac8ef93371a07",
      "blocked": null, "fingerprint": ["Cloudflare"] },
    { "country": "jp", "ok": false, "error": "upstream_timeout" }
  ],
  "checked": 2,
  "consistent": true,
  "charged": 0.0040008
}

Only countries that answered are billed. consistent compares content_hash across countries that weren't blocked.

GET

/api/inspect

$0.001 + bandwidth

Follows redirects one hop at a time (up to 10) and reports the chain, the CDN or WAF in front of the site, and which security headers are set.

QueryTypeDescription
urlrequiredstringURL-encoded http or https URL.
type, country, city, asn, sessionstringExit targeting.
request
curl -G https://nullroute.176-97-210-16.sslip.io/api/inspect \
  -H "Authorization: Bearer $NULLROUTE_KEY" \
  --data-urlencode "url=http://vercel.com" -d country=us
response
{
  "url": "http://vercel.com",
  "final_url": "https://vercel.com/",
  "status": 200,
  "redirects": [
    { "url": "http://vercel.com/", "status": 308, "location": "https://vercel.com/" },
    { "url": "https://vercel.com/", "status": 200, "location": null }
  ],
  "hops": 2,
  "headers": { "server": "Vercel", "x-vercel-id": "fra1::…", … },
  "fingerprint": ["Vercel"],
  "security": {
    "present": ["strict-transport-security", "content-security-policy", "x-content-type-options",
                "x-frame-options", "referrer-policy"],
    "missing": ["permissions-policy"],
    "score": 83
  },
  "title": "Vercel",
  "blocked": null,
  "ttfb_ms": 290,
  "total_ms": 351,
  "country": "us",
  "charged": 0.0010732
}
GET

/api/dns

$0.0002

Resolves a hostname over DNS-over-HTTPS through an exit, so you see the answers a visitor in that country gets.

QueryTypeDescription
namerequiredstringHostname, e.g. example.com.
typestringA (default), AAAA, CNAME, MX, TXT, NS, SOA, SRV, HTTPS.
countrystringExit country. Default us.
request
curl -H "Authorization: Bearer $NULLROUTE_KEY" \
  "https://nullroute.176-97-210-16.sslip.io/api/dns?name=example.com&type=A&country=de"
response
{
  "name": "example.com",
  "type": "A",
  "country": "de",
  "answers": [
    { "name": "example.com", "type": "A", "ttl": 214, "data": "23.192.228.80" },
    { "name": "example.com", "type": "A", "ttl": 214, "data": "23.215.0.136" }
  ],
  "answer_count": 2,
  "charged": 0.0002
}
GET

/api/exit-ip

$0.0002

Returns the public IP a request with these targeting options leaves from. Pass session to check which IP a sticky session holds.

QueryTypeDescription
type, country, city, asn, sessionstringExit targeting. Default res, us.
request
curl -H "Authorization: Bearer $NULLROUTE_KEY" \
  "https://nullroute.176-97-210-16.sslip.io/api/exit-ip?type=res&country=gb&session=4821"
response
{
  "exit_ip": "203.0.113.24",
  "exit_type": "res",
  "country": "gb",
  "session": "4821",
  "latency_ms": 640,
  "charged": 0.0002
}
POST

/api/proxy-test

$0.0005 / proxy

Checks whether proxies are alive, how fast they answer and which IP they exit from. Works with any provider's proxies, not just NullRoute.

FieldTypeDescription
proxiesrequiredstring[]1–200 lines: host:port, host:port:user:pass or scheme://user:pass@host:port. Schemes: http, https, socks4, socks5, socks5h.
timeout_msnumberPer proxy. Default 10000, max 30000.
request
curl https://nullroute.176-97-210-16.sslip.io/api/proxy-test \
  -H "Authorization: Bearer $NULLROUTE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"proxies":["socks5://user:pass@198.51.100.7:1080","198.51.100.9:8080"]}'
response
{
  "results": [
    { "proxy": "socks5://198.51.100.7:1080", "scheme": "socks5", "ok": true, "alive": true,
      "status": 200, "latency_ms": 312, "exit_ip": "198.51.100.7" },
    { "proxy": "http://198.51.100.9:8080", "scheme": "http", "ok": true, "alive": false,
      "latency_ms": 10004, "error": "timeout" }
  ],
  "tested": 2,
  "alive": 1,
  "dead": 1,
  "charged": 0.001
}

Lines that can't be parsed come back with "ok": false and aren't billed.

GET

/api/detect

$0.0001 / IP

Tells you whether an IP belongs to a known proxy or VPN provider, and which one. Use the bulk form for lists up to 1,000 addresses.

RequestParametersDescription
GET /api/detectipOne address. Master key only.
POST /api/detect/bulkips: string[]Up to 1,000 addresses, de-duplicated before billing. 10 calls per minute.
request
curl https://nullroute.176-97-210-16.sslip.io/api/detect/bulk \
  -H "Authorization: Bearer $NULLROUTE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ips":["198.51.100.7","203.0.113.24","10.0.0.1"]}'
response
{
  "results": [
    { "ip": "198.51.100.7", "status": "proxy", "proxy": true, "providers": ["ExampleVPN"] },
    { "ip": "203.0.113.24", "status": "clean", "proxy": false, "providers": [] },
    { "ip": "10.0.0.1", "status": "unknown", "proxy": false, "providers": [] }
  ],
  "checked": 2,
  "proxies": 1,
  "clean": 1,
  "charged": 0.0002
}

Status is proxy, clean, unknown (private address or no data, free) or invalid (not an IP, free).

Resellers

Reseller API

Для реселлеров: выпускайте ключи клиентам из своего бота или сайта — срок, скорость и лимит трафика задаются в одном запросе, трафик списывается с вашего баланса по оптовой цене.

Issue proxy keys to your customers from your own shop or bot. Each key gets an expiry, a speed cap and an optional traffic cap; its traffic is charged to your balance at your wholesale price.

  • Base URL: https://nullroute.176-97-210-16.sslip.io/api/v1/reseller. JSON in, JSON out.
  • Auth: Authorization: Bearer op-…, your master key from Settings. Sub-keys are refused with 401 use_master_key.
  • Accounts without reseller access get 403 not_a_reseller; a paused reseller account gets 403 reseller_disabled.
  • No access yet? Unlock it from Billing for a one-off $170 — that buys the rights only (API, wholesale rates, client keys); traffic keeps billing your balance. An admin can re-price it or attach your domain afterwards.
  • When your balance reaches $0, every key you issued stops authenticating. When a key expires, is disabled or runs out of traffic, its open tunnels close within about 30 seconds.
shell
export PROXY_API_KEY="op-your-master-key"
export API="https://nullroute.176-97-210-16.sslip.io/api/v1/reseller"
RequestDoes
GET /balanceBalance, wholesale price per GB and GB left per exit type.
POST /keysCreate a key. Returns 201 and the key object.
GET /keysList keys. Query: status=active|expired|disabled, limit (default 100, max 1000), offset.
GET /keys/:keyOne key. 404 not_found if it isn't yours.
PATCH /keys/:keyExtend, disable, re-enable, change speed, traffic cap or label.
DELETE /keys/:keyDelete the key. Returns {"success": true}.
GET /keys/:key/usageHourly traffic. Query hours, default 24, max 2160.

Create a key

FieldTypeDescription
hours or daysnumberLifetime. Default 1 day, max 365 days. If both are sent, hours wins.
speed_mbpsnumberShared by all the key's connections. 0 = no cap, max 10000.
traffic_gbnumberTraffic cap. 0 or absent = unlimited.
allowed_typesstringComma list of res, dc, mob. Empty = all.
labelstringYour note, e.g. the customer's order id.
request · 2 hours, 500 Mbps
curl -X POST $API/keys \
  -H "Authorization: Bearer $PROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hours":2,"speed_mbps":500,"label":"order-1042"}'
response · 201
{
  "key": "sk-3f9c…",
  "label": "order-1042",
  "active": true,
  "expired": false,
  "created_at": "2026-10-05T12:00:00Z",
  "expires_at": "2026-10-05T14:00:00Z",
  "speed_mbps": 500,
  "traffic_limit_gb": null,
  "traffic_used_gb": 0.0,
  "cost_usd": 0.0,
  "allowed_types": "",
  "online": false,
  "now_mbps": 0.0,
  "connect": {
    "host": "nullroute.176-97-210-16.sslip.io",
    "port": 32424,
    "username_example": "res-any",
    "http": "http://res-any:sk-3f9c…@nullroute.176-97-210-16.sslip.io:32424",
    "socks5": "socks5://res-any:sk-3f9c…@nullroute.176-97-210-16.sslip.io:32424",
    "line": "nullroute.176-97-210-16.sslip.io:32424:res-any:sk-3f9c…"
  }
}

Send connect.line or connect.http to the customer as is. They can change res-any to any targeting username. Errors: 400 invalid_duration, invalid_speed, invalid_traffic_gb, invalid_allowed_types; 402 insufficient_balance when your balance is $0 or less.

Manage keys

PATCH takes any of extend_hours (added to the current expiry, or to now if the key already expired), active, speed_mbps, traffic_gb, label, and returns the updated key object.

curl
K=sk-3f9c…

# Extend by 24 hours
curl -X PATCH $API/keys/$K -H "Authorization: Bearer $PROXY_API_KEY" \
  -H "Content-Type: application/json" -d '{"extend_hours":24}'

# Disable now (re-enable with {"active":true})
curl -X PATCH $API/keys/$K -H "Authorization: Bearer $PROXY_API_KEY" \
  -H "Content-Type: application/json" -d '{"active":false}'

# Delete
curl -X DELETE $API/keys/$K -H "Authorization: Bearer $PROXY_API_KEY"

# Balance and hourly usage
curl $API/balance -H "Authorization: Bearer $PROXY_API_KEY"
curl "$API/keys/$K/usage?hours=24" -H "Authorization: Bearer $PROXY_API_KEY"
GET /balance
{
  "balance_usd": 42.5,
  "wholesale_per_gb": { "res": 0.35, "dc": 0.12, "mob": 0.6 },
  "gb_left": { "res": 121.43, "dc": 354.17, "mob": 70.83 },
  "gateway": "nullroute.176-97-210-16.sslip.io"
}
GET /keys/:key/usage
{
  "points": [
    { "hour": "2026-10-05T12:00:00Z", "bytes": 73400320 },
    { "hour": "2026-10-05T13:00:00Z", "bytes": 18874368 }
  ]
}

Hours are UTC. Hours without traffic are left out.

Example: sell a key from a bot

python
import os, requests

API = "https://nullroute.176-97-210-16.sslip.io/api/v1/reseller"
HEADERS = {"Authorization": f"Bearer {os.environ['PROXY_API_KEY']}"}

def sell_key(order_id: str, hours: int, mbps: int = 0, gb: float = 0) -> str:
    """Call after payment. Returns the text to send to the customer."""
    r = requests.post(f"{API}/keys", headers=HEADERS, timeout=15, json={
        "label": order_id, "hours": hours,
        "speed_mbps": mbps, "traffic_gb": gb,
    })
    if r.status_code == 402:
        raise RuntimeError("Reseller balance is empty: top up before selling")
    r.raise_for_status()
    k = r.json()
    return (f"Your proxy (valid until {k['expires_at']} UTC):\n"
            f"{k['connect']['line']}\n"
            f"HTTP: {k['connect']['http']}")

# bot.send_message(chat_id, sell_key("tg-551-1042", hours=24, mbps=100))

Reference

Pricing and limits

Prepaid balance in USD; top up from $5 in the dashboard. Proxy traffic is billed per byte in both directions at the exit type's rate.

Exit typeUsernamePer GB
Residentialres$0.60
Datacenterdc$0.20
Mobilemob$1.00
ToolPricePer minuteBatch limit
POST /api/fetch$0.001 + bandwidth3008 MB body
Smart retry+$0.001 when a retry succeeds—3 attempts
POST /api/geo-check$0.002 / country + bandwidth6015 countries
GET /api/inspect$0.001 + bandwidth12010 redirects
GET /api/dns$0.0002300—
GET /api/exit-ip$0.0002120—
POST /api/proxy-test$0.0005 / proxy30200 proxies
/api/detect$0.0001 / IP120 · bulk 101,000 IPs

"Bandwidth" is the response size at the exit type's per-GB rate. Rate limits are per account; going over returns 429 rate_limited. A daily spend limit and per-key caps are set in Dashboard → API keys.

Reference

API errors

API errors are JSON with an HTTP status and a stable code:

response
HTTP/1.1 402 Payment Required
{ "error": "insufficient_balance" }
StatusCodeWhat to do
400invalid_url, invalid_schemeSend a full http or https URL.
400invalid_type, invalid_country, invalid_city, invalid_asn, invalid_sessionCheck the targeting fields against the username format.
400invalid_name, invalid_ip, missing_ipSend a valid hostname or IP address.
400no_countries, too_many_countries, no_proxies, too_many_proxies, no_ips, too_many_ipsStay within the batch limits in pricing and limits.
401missing_api_key, invalid_api_keySend Authorization: Bearer <key> with a current key.
401key_disabled, key_expiredRe-enable the sub-key or create a new one.
402insufficient_balanceTop up in Billing.
402spend_limit_reached, quota_exceededDaily limit or sub-key cap hit. Raise it, or wait for 00:00 UTC.
403exit_not_allowedThe sub-key doesn't allow that exit type or country.
429rate_limitedBack off and retry after a few seconds.
502target_unreachable, probe_failed, resolve_failed, too_many_redirectsThe exit couldn't complete the request. Retry; you aren't charged.

Proxy connection errors (407, 502, 403) are covered in troubleshooting.