Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hypercall

A residential proxy network. You connect with a standard HTTP or SOCKS5 proxy client, and your traffic exits through a real residential IP in the location you choose.

Everything is controlled through the proxy username: geo targeting, sticky sessions, TTL, and speed are all option tokens appended to it, so any client that supports username/password proxy auth works with no SDK and no special integration.

curl -x 'http://USER-country-us:PASS@proxy.hypercall.dev:4444' https://api.ipify.org

How it works

  • One endpoint. proxy.hypercall.dev automatically routes you to the nearest entry point. You never pick a region; the exit location you want goes in the username.
  • Targeting is measured, not claimed. Exits are indexed by their real, verified location and network, so country, state, city, and asn reflect where the IP actually is.
  • Pay for what you transfer. Your balance is metered in bytes (1 GB = 1,000,000,000 bytes). When it runs out, requests stop with 402.

Where to start

QuickstartYour first request, in one command
ConnectingPorts, protocols, proxy-string formats
Targeting optionsThe full username token grammar
Error codesWhat each failure means and how to fix it
API referenceManage accounts and sub-users over REST

Quickstart

You need the username and password issued when your account was created.

1. Make a request

curl -x 'http://USER:PASS@proxy.hypercall.dev:4444' https://api.ipify.org

The response is the residential exit IP your request came from. Run it again and you will get a different one; by default, every request rotates to a fresh exit.

Quote the URL. Passwords can contain characters (@ : / # %) that a shell or a URL parser will mangle, which shows up as a confusing 407. Single-quote the whole -x value, or pass credentials with --proxy-user instead:

curl -x http://proxy.hypercall.dev:4444 --proxy-user 'USER:PASS' https://api.ipify.org

2. Pick a country

Append option tokens to the username, not the host:

curl -x 'http://USER-country-de:PASS@proxy.hypercall.dev:4444' https://api.ipify.org

Now the exit is in Germany. See Targeting options for state, city, ASN, and more.

3. Keep the same IP across requests

Add a session id (sid), which can be any string you choose. Requests with the same sid reuse the same exit:

curl -x 'http://USER-country-us-sid-abc123:PASS@proxy.hypercall.dev:4444' https://api.ipify.org
curl -x 'http://USER-country-us-sid-abc123:PASS@proxy.hypercall.dev:4444' https://api.ipify.org

Both return the same IP. See Sticky sessions for how long that lasts.

4. Use it from code

Any HTTP client with proxy support works. Nothing Hypercall-specific:

import requests

proxy = "http://USER-country-us:PASS@proxy.hypercall.dev:4444"
r = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy})
print(r.text)
import { HttpsProxyAgent } from 'https-proxy-agent';

const agent = new HttpsProxyAgent('http://USER-country-us:PASS@proxy.hypercall.dev:4444');
const res = await fetch('https://api.ipify.org', { agent });
console.log(await res.text());

Next

Connecting

Endpoint

Hostproxy.hypercall.dev (routes to the nearest entry point)
HTTP4444, 8888
SOCKS51080

Those are the conventional assignments, but every port accepts both protocols; the protocol is detected per connection, so a SOCKS5 client pointed at 4444 works too. 8888 exists because some clients default to it. Regional hostnames (us.proxy.hypercall.dev, eu.proxy.hypercall.dev) let you connect directly to a region you already know you want. This does not change the exit location, only where you enter the network.

Protocols

HTTP: both plain forward proxying and CONNECT for HTTPS.

curl -x 'http://USER-country-us:PASS@proxy.hypercall.dev:4444' https://example.com

SOCKS5: CONNECT only. Hostnames are resolved at the exit (socks5h-style), so DNS never leaks from your machine.

curl -x 'socks5h://USER-country-us:PASS@proxy.hypercall.dev:1080' https://example.com

SOCKS5 UDP ASSOCIATE is not supported. UDP requests are rejected cleanly with SOCKS reply 0x07.

Proxy-string formats

Most tools accept one of these. host:port:user:pass is a common format for automation tools:

proxy.hypercall.dev:4444:USER-country-us:PASS
http://USER-country-us:PASS@proxy.hypercall.dev:4444
socks5h://USER-country-us:PASS@proxy.hypercall.dev:1080

You can generate ready-made strings, including sticky ids spread across sessions, from the API:

curl -H "Authorization: Bearer $HYPERCALL_KEY" \
  'https://api.hypercall.dev/api/me/proxies?country=us&count=5&format=txt'

See the API reference for the parameters.

IP authentication

Instead of username/password, an account can authorise by source IP: you register your IPs, connect with no credentials, and the account is identified by where you’re connecting from. IP auth runs on a dedicated port that is enabled on request: contact support to have it set up for your account before relying on it.

Register the IPs with:

curl -H "Authorization: Bearer $HYPERCALL_KEY" -X PUT \
  -H 'Content-Type: application/json' \
  -d '{"ips": ["203.0.113.7"]}' \
  https://api.hypercall.dev/api/users/<id>/ip-auths

With IP auth you cannot pass option tokens (there’s no username to put them in), so requests use the account’s defaults.

Restricting where credentials can be used

Separately, you can restrict a username/password account to a set of source networks. Requests from anywhere else are refused even with valid credentials:

curl -H "Authorization: Bearer $HYPERCALL_KEY" -X PUT \
  -H 'Content-Type: application/json' \
  -d '{"cidrs": ["203.0.113.0/24"]}' \
  https://api.hypercall.dev/api/users/<id>/allowed-ips

An empty list means unrestricted. The check always uses the real connecting address, never a forwarded header.

Targeting options

Options are -key-value pairs appended to your username, freely combinable and order-independent:

USER-country-us-state-texas-city-houston-sid-s42-ttl-30

Everything before the first known option key is your account username, so a username containing hyphens still works.

Geo

OptionValuesNotes
countryISO-2 code, or anycountry-us. any = no country constraint
state / regionname or codeAliases for the same thing: state-texas
citynamecity-houston. Approximate; see the caveat below
asnnumber, AS prefix optionalasn-7922 and asn-AS7922 are equivalent
zippostal codezip-77002
continenteurope, asia, africa, northamerica, southamerica, oceania, or the short codes eu, as, af, na, sa, ocExpands to one country in that continent; an explicit country wins

Multi-word values use no spaces: state-newyork, city-sanfrancisco.

City accuracy. Country, state, and ASN come from a verified measurement of each exit and are reliable. City is approximate: city-level location data is inherently less precise for residential connections. If exact city matters, verify the exit yourself and treat the label as a hint.

Session

OptionValuesDefaultNotes
sid / sessionany string, ≤60 charsnoneSame sid → same exit. See Sticky sessions
ttlminutes, 10-144010 minHow long a sid stays pinned. Clamped into range
strictfalse/0/off/no to disableonSee below
speed1-10nonePrefer faster exits within the matched set
qualitylow, medium (or med), highnoneFilters on measured network class; high restricts to residential-grade lines
mobileflag (no value)offMobile-carrier exits only

ttl is minutes in the username. ttl-30 is thirty minutes.

Strict mode

Strict is on by default: if nothing matches your exact target, you get 417 rather than a silently broader exit. This matters: a “US, Texas, Comcast” request should never quietly return a random US IP.

Turn it off to allow progressive widening (asncityzipstate; country and session are never dropped):

USER-country-us-state-texas-city-houston-strict-false

Only false, 0, off, and no disable it. Any other value leaves it on.

Examples

# Rotating US residential
USER-country-us

# A specific carrier
USER-country-us-asn-7922

# Mobile only, high quality
USER-country-gb-mobile-quality-high

# Sticky for 30 minutes
USER-country-de-sid-checkout-42-ttl-30

# City, but accept broader if unavailable
USER-country-us-city-houston-strict-false

# Fastest available exit in Japan
USER-country-jp-speed-10

Sticky sessions

By default every request rotates to a fresh exit. To hold one IP across requests, pick any sid:

USER-country-us-sid-mysession-ttl-30

Every request carrying that sid routes to the same exit, for up to ttl minutes. Different sid values are independent, so you can run many sticky identities in parallel under one account.

# Two independent identities, each with its own stable IP
curl -x 'http://USER-country-us-sid-cart-a:PASS@proxy.hypercall.dev:4444' https://api.ipify.org
curl -x 'http://USER-country-us-sid-cart-b:PASS@proxy.hypercall.dev:4444' https://api.ipify.org

How long a session really lasts

Stickiness is best-effort, and this is the single most important thing to design around. ttl is an upper bound you request, not a guarantee.

The exit is a real residential device, and it can go offline at any time. When that happens, your sid moves to another exit that matches the same targeting options, and the IP changes mid-session.

Practical expectations:

  • Requesting a long ttl does not make a device stay online.
  • Holds beyond ~30 minutes are unreliable regardless of ttl.
  • Short sessions (a checkout flow, a login sequence) are very reliable.

Write your client to tolerate a mid-session IP change. If your workflow breaks when the IP moves, re-verify the exit at the start of each critical step rather than assuming continuity:

def exit_ip(session_id):
    p = f"http://USER-country-us-sid-{session_id}-ttl-30:PASS@proxy.hypercall.dev:4444"
    return requests.get("https://api.ipify.org",
                        proxies={"http": p, "https": p}, timeout=30).text

ip = exit_ip("checkout-1")
# ... later, before a step that must run from the same IP:
if exit_ip("checkout-1") != ip:
    restart_flow()   # the device rotated; don't continue on a new identity

Choosing a sid

Any string up to 60 characters. Longer values are truncated. Use something meaningful to your workflow, such as an order id, a worker number, or a customer id, so concurrent jobs don’t collide on the same exit unintentionally.

Error codes

Errors come back as HTTP status codes on the proxy connection (or the equivalent SOCKS5 reply byte).

CodeMeaningWhat to do
402Data limit reached. Your byte balance is exhaustedTop up. Check with /stats
407Proxy authentication required. Bad or missing credentialsSee below; this is the most commonly misdiagnosed one
417No exit for that location. Nothing matched your targetLoosen the target, or add strict-false
429Too many connections. Account thread cap reachedLower concurrency, or ask for a higher cap
502Upstream failed. A temporary failure on the exit connectionRetry; a new exit is chosen

SOCKS5 equivalents: 0x02 when the data limit or connection cap is reached, 0x04 when no exit matches your target, 0x07 for an unsupported command (e.g. UDP ASSOCIATE), 0x01 for a general or upstream failure.

Debugging 407

A 407 means the credentials we received were not valid. The most common cause is not a wrong password: it is the password being mangled before it ever leaves your machine.

Passwords can contain @, :, /, #, %. Inside a proxy URL those are structural characters, so a parser splits the string in the wrong place and sends the wrong credentials:

# WRONG: the password is parsed as part of the URL
curl -x http://USER:pa@ss/word@proxy.hypercall.dev:4444 https://api.ipify.org

# RIGHT: credentials passed separately, never parsed as a URL
curl -x http://proxy.hypercall.dev:4444 --proxy-user 'USER:pa@ss/word' https://api.ipify.org

# ALSO FINE: quoted, with the password percent-encoded
curl -x 'http://USER:pa%40ss%2Fword@proxy.hypercall.dev:4444' https://api.ipify.org

Work through this order:

  1. Re-test with --proxy-user (or your client’s separate credential fields). If it works, it was a URL-parsing problem, not the password.
  2. Check the account is active. A suspended account returns 407. GET /api/me shows status.
  3. Check source-IP restrictions. If the account has an allowed-ips list, requests from other networks are refused.
  4. Rotate the password if you believe it leaked; see Credentials.

Debugging 417

417 means strict mode found no exit matching your exact target. Either the combination is too narrow (a specific ASN in a specific small city), or coverage for it is momentarily thin.

# Narrow: may return 417
USER-country-us-state-wyoming-city-cody-asn-7922

# Same intent, tolerant of thinner coverage
USER-country-us-state-wyoming-city-cody-asn-7922-strict-false

With strict-false the target widens step by step (asncityzipstate) until something matches. Country and session are never dropped.

Usage & limits

Byte convention

Everything is metered in bytes, where 1 GB = 1,000,000,000 bytes (decimal, not 2³⁰). A “10 GB” balance is exactly 10000000000 bytes.

Usage counts both directions: bytes sent upstream plus bytes received.

Checking your balance

With your API key:

curl -H "Authorization: Bearer $HYPERCALL_KEY" https://api.hypercall.dev/api/me
{
  "id": "6f1c1f8e-6f0a-4b8f-9a5e-2f9d1c3b7a10",
  "parent_id": null,
  "can_resell": true,
  "name": "acme",
  "status": "active",
  "proxy_username": "acme",
  "proxy_password": "<your proxy password>",
  "stats_token": "<opaque token>",
  "max_bytes": 500000000000,
  "allocated_bytes": 0,
  "bytes_used": 2885007,
  "remaining_bytes": 499997114993,
  "thread_cap": null,
  "speed_limit_mbps": null,
  "expires_at": null,
  "ip_auths": [],
  "ip_restrictions": [],
  "created_at": "2026-01-12T09:30:00Z"
}
FieldMeaning
max_bytesYour total budget. null = unlimited
bytes_usedConsumed by your own proxy traffic
allocated_bytesHanded down to sub-users (see below)
remaining_bytesmax_bytes − allocated_bytes − bytes_used
statusactive, suspended, depleted, or expired

The public stats endpoint

Each account has an opaque stats_token for unauthenticated usage checks. This is useful for dashboards, or for handing a customer a read-only link without giving them an API key.

curl https://api.hypercall.dev/stats/<stats_token>
curl 'https://api.hypercall.dev/stats/<stats_token>?format=txt'
used=2885007 total=500000000000 remaining=499997114993

On unlimited accounts, total and remaining read unlimited.

The token exposes usage only: no credentials, no ability to change anything.

Limits

LimitEffect when hit
Byte budgetRequests stop with 402
thread_capConcurrent connections over the cap get 429
speed_limit_mbpsThroughput shaped to the cap; requests still succeed
expires_atAfter this time the account stops serving

Limits apply the moment they’re hit. In-flight connections are cut when a budget runs out, not just new ones.

Sub-users

If your account can resell, you can create sub-users and carve your budget between them:

curl -H "Authorization: Bearer $HYPERCALL_KEY" -X POST \
  -H 'Content-Type: application/json' \
  -d '{"name": "customer-a", "gb": 50}' \
  https://api.hypercall.dev/api/users

That moves 50 GB out of your balance into theirs: your allocated_bytes rises, your remaining_bytes falls. Sub-users get their own credentials, their own stats token, and their own limits.

Allocated data belongs to the sub-user: their consumption does not draw on your bytes_used again, and you can only reclaim what they haven’t spent:

# Take back everything unused
curl -H "Authorization: Bearer $HYPERCALL_KEY" -X POST \
  https://api.hypercall.dev/api/users/<id>/refund

If you allocate your entire budget out, you stop serving (your remaining is 0) while your sub-users keep running, because they already own those bytes.

Credentials

Each account has two independent secrets:

Used forLooks like
Proxy passwordAuthenticating proxy connectionsshort random string
API keyAuthenticating REST callsuk_ + hex

Rotating one does not affect the other.

Rotating the proxy password

curl -H "Authorization: Bearer $HYPERCALL_KEY" -X POST \
  https://api.hypercall.dev/api/me/rotate-password
{ "proxy_password": "<new password>" }

The new password is shown exactly once. It cannot be retrieved later, so store it before you close the terminal.

Rotation takes effect across the network within seconds. Connections using the old password stop working, so roll it when you can update your clients.

Rotating the API key

curl -H "Authorization: Bearer $HYPERCALL_KEY" -X POST \
  https://api.hypercall.dev/api/me/rotate-key
{ "api_key": "uk_..." }

This mints a fresh key and revokes every other key on the account, including the one you just authenticated with. This is deliberate: it is designed for the case where a key may have leaked, and it guarantees no forgotten key survives. Switch to the returned key immediately.

Rotating a sub-user’s password

Parents can roll a sub-user’s proxy password without knowing the old one:

curl -H "Authorization: Bearer $HYPERCALL_KEY" -X POST \
  https://api.hypercall.dev/api/users/<id>/rotate-password

If something leaks

  1. Rotate immediately: password, key, or both.

  2. Check usage on /api/me; unexpected bytes_used is the clearest sign a credential was used by someone else.

  3. Restrict by source IP so credentials alone aren’t enough:

    curl -H "Authorization: Bearer $HYPERCALL_KEY" -X PUT \
      -H 'Content-Type: application/json' \
      -d '{"cidrs": ["203.0.113.0/24"]}' \
      https://api.hypercall.dev/api/users/<id>/allowed-ips
    

Handling passwords safely

Proxy passwords can contain @ : / # %. Never paste one raw into a proxy URL: it gets misparsed, and you’ll chase a 407 that has nothing to do with the password being wrong. Use your client’s separate credential fields, or percent-encode.

API overview

Base URL: https://api.hypercall.dev

SurfaceAuthWhat
/api/*Authorization: Bearer uk_…Your account and your sub-users
/stats/{token}noneUsage by opaque token
/locations/*noneAvailable countries, regions, cities, ASNs

The full machine-readable spec is openapi.yaml. Import it into Postman or Insomnia, or generate a client from it.

Authentication

curl -H "Authorization: Bearer $HYPERCALL_KEY" https://api.hypercall.dev/api/me

A missing or invalid key returns:

{ "message": "Invalid API key." }

Errors

StatusBodyMeaning
401{"message": "Invalid API key."}Bad or missing credentials
403{"message": "..."}Account inactive, or lacks the capability
404{"message": "Not found."}Not found, or not yours (see below)
422{"message": "..."}Validation error
422{"error": "..."}Billing error, e.g. insufficient balance

Note the two distinct 422 shapes: message means the request was malformed; error means the request was valid but there is a billing problem, such as insufficient balance.

404 is deliberately ambiguous. Asking about a sub-user that isn’t yours returns 404, not 403; the API never confirms that an account you don’t own exists.

Idempotency

Creating a sub-user (POST /api/users) and allocating data (POST /api/users/{id}/allocate) accept an Idempotency-Key header. Retrying with the same key replays the original response instead of doing the work twice:

curl -H "Authorization: Bearer $HYPERCALL_KEY" \
     -H 'Idempotency-Key: order-4417' \
     -X POST -H 'Content-Type: application/json' \
     -d '{"name": "customer-a", "gb": 50}' \
     https://api.hypercall.dev/api/users

Use it for anything triggered by a queue, a webhook, or a user clicking twice.

The account model

Every account is the same kind of object. parent_id describes the whole hierarchy:

  • parent_id: null: a top-level account.
  • parent_id set: a sub-user, created by (and drawing budget from) its parent.

can_resell gates whether an account may create sub-users. Nesting can go as deep as you need: a sub-user with can_resell can carve its own budget further down, using the identical endpoints.

Bytes follow one rule everywhere:

remaining = max_bytes − allocated_bytes − bytes_used

allocated_bytes is what you’ve handed to sub-users; bytes_used is your own proxy traffic. A parent pays once, at allocation. A sub-user’s consumption never draws on the parent again.

Reference

Base URL: https://api.hypercall.dev

Authenticate /api/* calls with your API key:

curl -H "Authorization: Bearer $HYPERCALL_KEY" https://api.hypercall.dev/api/me

/stats/{token} and /locations/* need no authentication.

Prefer a machine-readable spec? Download openapi.yaml and import it into Postman, Insomnia, or your client generator.

Your account

GET /api/me

Your account summary. Returns every account field:

{
  "id": "6f1c1f8e-6f0a-4b8f-9a5e-2f9d1c3b7a10",
  "parent_id": null,
  "can_resell": true,
  "name": "acme",
  "status": "active",
  "proxy_username": "acme",
  "proxy_password": "<your proxy password>",
  "stats_token": "<opaque token>",
  "max_bytes": 500000000000,
  "allocated_bytes": 0,
  "bytes_used": 2885007,
  "remaining_bytes": 499997114993,
  "thread_cap": null,
  "speed_limit_mbps": null,
  "expires_at": null,
  "ip_auths": [],
  "ip_restrictions": [],
  "created_at": "2026-01-12T09:30:00Z"
}

status is one of active, suspended, depleted, expired. max_bytes: null means unlimited. See Usage & limits for what the byte fields mean.

GET /api/me/proxies

Generate ready-to-use proxy strings.

Query paramMeaning
country, state, city, asn, zip, continentTargeting, same values as the username options
sidExplicit sticky session id, up to 60 chars. Not combinable with count > 1
count1 to 100, default 1. Each line gets its own random session id
ttlSticky TTL in minutes, 10 to 1440
strictfalse/0/off/no to allow widening
formatjson (default) or txt for host:port:user:pass lines
curl -H "Authorization: Bearer $HYPERCALL_KEY" \
  'https://api.hypercall.dev/api/me/proxies?country=us&count=5&format=txt'

JSON responses are an array of:

{
  "server": "us-east",
  "host": "us.proxy.hypercall.dev",
  "username": "acme-country-us-sid-48291057",
  "password": "<proxy password>",
  "http_port": 4444,
  "socks5_port": 1080,
  "http_url": "http://acme-country-us-sid-48291057:<password>@us.proxy.hypercall.dev:4444",
  "socks5_url": "socks5://acme-country-us-sid-48291057:<password>@us.proxy.hypercall.dev:1080"
}

POST /api/me/rotate-password

Returns {"proxy_password": "..."} exactly once. See Credentials.

POST /api/me/rotate-key

Returns {"api_key": "uk_..."} and revokes every other key on the account, including the one used for this request.

GET /api/nodes

Entry nodes you can connect to:

[{ "id": "...", "name": "us-east", "host": "us.proxy.hypercall.dev", "region": "us", "http_port": 4444, "socks5_port": 1080 }]

Sub-users

All sub-user routes require can_resell on your account and only ever see your own sub-users; anyone else’s return 404.

POST /api/users

Create a sub-user and fund it from your balance. Accepts an Idempotency-Key header.

Body fieldMeaning
nameRequired
gbBudget in GB. Omit or null for unlimited (only from an unlimited parent)
can_resellDefault false
proxy_username / proxy_passwordGenerated when omitted
thread_cap, speed_limit_mbpsOptional limits
expires_daysDays until the account stops serving
curl -H "Authorization: Bearer $HYPERCALL_KEY" -X POST \
  -H 'Content-Type: application/json' \
  -d '{"name": "customer-a", "gb": 50}' \
  https://api.hypercall.dev/api/users

Returns {"user": {...}, "api_key": "uk_..."}. The key is shown once.

GET /api/users and GET /api/users/{id}

List your sub-users, or fetch one. Same shape as GET /api/me.

PATCH /api/users/{id}

Update name, status (active or suspended only), can_resell, thread_cap, or speed_limit_mbps. depleted and expired are computed states and cannot be set.

DELETE /api/users/{id}

Returns {"deleted": true}. The sub-user’s unused balance returns to you.

POST /api/users/{id}/allocate

Body {"gb": 25}. Moves GB from your balance into theirs. Accepts an Idempotency-Key header. Insufficient balance returns a billing 422.

POST /api/users/{id}/refund

Body {"gb": 10}, or an empty body to reclaim everything they haven’t spent.

POST /api/users/{id}/rotate-password

Returns {"proxy_password": "..."} once. You never need the old one.

PUT /api/users/{id}/allowed-ips

Body {"cidrs": ["203.0.113.0/24"]}. Restricts where the sub-user’s credentials work. Empty list = unrestricted. Returns {"allowed_ips": [...]}.

PUT /api/users/{id}/ip-auths

Body {"ips": ["203.0.113.7"]}. Source IPs that authenticate as this account with no password (see IP authentication). Returns {"ip_auths": [...]}.

GET /api/users/{id}/proxies

Same parameters and response as /api/me/proxies, for a sub-user.

Public (no auth)

GET /stats/{token}

Usage by the account’s opaque stats_token. Add ?format=txt for used=... total=... remaining=... (with unlimited on unlimited accounts). See Usage & limits.

GET /locations/...

What the network can currently serve, as flat JSON arrays of strings:

EndpointFilters
/locations/countriesnone
/locations/regions?country=us
/locations/cities?country=us&region=texas
/locations/asns?country=us
curl 'https://api.hypercall.dev/locations/cities?country=us&region=texas'

Errors

See API overview for status codes and the two 422 shapes.