# Authentication
Source: https://docs.roundproxies.com/datacenter/authentication
Authenticate with Datacenter Proxies using username/password or IP whitelisting.
Datacenter proxies support two ways to authenticate. Pick whichever fits your setup — both can be active at the same time.
## Username & Password
The default method, and the one that works everywhere. Your credentials are included in every request:
```text theme={null}
http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}
```
You'll find your username and password in the [dashboard](https://app.roundproxies.com/dashboard/datacenter), and you can reset them there at any time. Resetting takes effect within a few minutes — update any running scripts before you rotate credentials, or they'll start failing with `407` errors.
Some tools (older browser extensions, certain game clients) can't handle proxy credentials. If yours is one of them, use IP whitelisting instead.
## IP Whitelisting
Instead of sending credentials, you register the IP of the machine that will use the proxies. Requests coming from a whitelisted IP go through without a username or password:
```text theme={null}
http://{PROXY_IP}:{PORT}
```
To set it up:
1. Find your server's public IP (for example via [api.ipify.org](https://api.ipify.org))
2. Add it under **IP Whitelist** in the [dashboard](https://app.roundproxies.com/dashboard/datacenter)
3. Wait a minute or two for the change to propagate, then test a request
Keep in mind:
* Whitelisting only helps if your machine has a **static** IP. If your ISP rotates your IP, requests will start failing with `407` until you update the whitelist.
* You can whitelist multiple IPs, e.g. your production server and your office.
* Remove IPs you no longer use — anyone on a whitelisted IP can use your bandwidth.
## Troubleshooting
| Problem | Likely cause | Fix |
| ----------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `407 Proxy Authentication Required` | Wrong credentials, or your IP isn't whitelisted. | Double-check credentials in the dashboard; confirm your current public IP matches the whitelist. |
| Works locally but not on the server | The server's IP isn't whitelisted. | Whitelist the server's public IP, or use username/password on the server. |
| Worked yesterday, fails today | Your ISP changed your IP, or credentials were reset. | Re-check your public IP and the whitelist; confirm credentials are current. |
Still stuck? See [Error Handling](/datacenter/error-handling) or email [team@roundproxies.com](mailto:team@roundproxies.com).
# Basics
Source: https://docs.roundproxies.com/datacenter/basics
How our Datacenter Proxies work and how to set them up.
Datacenter proxies run on servers in data centers instead of real consumer devices. That makes them much faster and cheaper than residential proxies — they come with unlimited bandwidth and are billed per IP, not per GB. The trade-off: some sites can tell they're not home connections, so heavily protected targets may block them.
This is a developer guide: For easy and fast proxy creation head over to your Datacenter dashboard and create proxies there. Here is the dashboard link: [https://app.roundproxies.com/dashboard/datacenter](https://app.roundproxies.com/dashboard/datacenter)
## When to use them
Datacenter proxies are the right choice when speed and cost matter more than looking like a regular home user:
* Scraping sites with little or no bot protection
* SEO and rank tracking
* Ad verification
* Load testing your own services
* Accessing geo-restricted content that doesn't block datacenter IPs
If your target site blocks datacenter IPs (frequent `403` responses, captchas on every request), switch to [Residential Proxies](/residentials/basics) instead.
## Proxy Format
Unlike residential proxies, datacenter proxies are dedicated — you get a fixed list of IPs that belong to you for the length of your plan. The dashboard gives you each proxy in this format:
```text theme={null}
IP:PORT:USERNAME:PASSWORD
```
### Components Breakdown
| Component | Description | Example |
| ------------ | ----------------------- | --------------- |
| **IP** | Your dedicated proxy IP | `192.0.2.10` |
| **Port** | Connection port | `8000` |
| **Username** | Your proxy username | `YOUR_USERNAME` |
| **Password** | Authentication password | `YOUR_PASSWORD` |
Because the IPs are dedicated, there's no session parameter — the IP never changes unless you replace it from the dashboard.
## Supported Protocols
All datacenter proxies support HTTP, HTTPS, and SOCKS5 on the same endpoint. Use whichever your tooling expects.
## Example Request
```python Python theme={null}
import requests
proxies = {
'http': 'http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}',
'https': 'http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}'
}
response = requests.get('https://api.ipify.org?format=json', proxies=proxies)
print(response.json())
```
```bash cURL theme={null}
curl -x "http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}" \
https://api.ipify.org?format=json
```
The response should return your proxy's IP, confirming the connection works.
## Tips
* Spread requests across all your IPs instead of hammering one — even dedicated IPs get rate-limited by target sites.
* If an IP gets banned by a target, replace it from the dashboard rather than retrying against the ban.
* You can skip credentials entirely by whitelisting your server's IP — see [Authentication](/datacenter/authentication).
* Something not working? Check [Error Handling](/datacenter/error-handling) for common errors and fixes.
# Error Handling
Source: https://docs.roundproxies.com/datacenter/error-handling
Common errors you may encounter when using Datacenter Proxies and how to resolve them.
When using Roundproxies datacenter proxies, you may run into errors from the proxy network or the target site. The tables below summarize the most common ones, what they mean, and how to fix them.
## Authentication Errors
| Error | Meaning | Fix |
| ----------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `407 Proxy Authentication Required` | Credentials missing, malformed, or incorrect. | Verify credentials in the [dashboard](https://app.roundproxies.com/dashboard/datacenter). If using IP whitelisting, confirm your current IP is added. |
| `401 Unauthorized` | Account recognized but request not allowed. | Confirm your subscription is active, not over quota, and that your plan includes the requested datacenter pool. |
## Connection Errors
| Error | Meaning | Fix |
| ------------------------------ | ------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `Connection Timed Out` | The proxy didn't respond in time. | Retry the request and use a closer datacenter region if available. |
| `Connection Refused` / `Reset` | Connection rejected or dropped mid-request. | Check firewall/outbound rules and confirm you're using the correct port for the endpoint. |
## IP / Pool Errors
| Error | Meaning | Fix |
| -------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `IP Banned by Target` | The datacenter IP is recognized and blocked by the destination. | Rotate to a new IP from the pool or switch to [Residential Proxies](/residentials/basics) for stricter targets. |
| `Dedicated IP Unavailable` | Your dedicated IP is offline or being replaced. | Wait a few minutes and retry — replacements happen automatically. Contact support if it persists. |
## HTTP Status Errors From the Target Site
These come from the destination website, not the proxy itself.
| Error | Meaning | Fix |
| ----------------------- | ------------------------------------- | --------------------------------------------------------------------------------- |
| `403 Forbidden` | Site is blocking the request. | Rotate IPs more aggressively; consider residential proxies for sensitive targets. |
| `429 Too Many Requests` | Site is rate-limiting your requests. | Slow the request rate and rotate IPs more often. |
| `5xx` | Server-side error on the target site. | Retry with exponential backoff; try a different IP from the pool. |
## Quota / Billing Errors
| Error | Meaning | Fix |
| ------------------------------------ | --------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `Bandwidth or Request Limit Reached` | Plan quota exhausted. | Upgrade your plan or wait for the next billing cycle. Monitor usage in the [dashboard](https://app.roundproxies.com). |
## Still stuck?
Reach out at [team@roundproxies.com](mailto:team@roundproxies.com) or visit the [Help Center](https://help.roundproxies.com/en).
# Home
Source: https://docs.roundproxies.com/index
Roundproxies is the all-in-one proxy platform for developers — residential and datacenter networks, sticky and rotating sessions, and a single API to plug into any tool or scraper.
Real-device IPs across 195+ countries for any target.
Fast, low-cost IPs for high-throughput workloads.
Static residential IPs hosted on datacenter infrastructure.
## Start building
Pick your stack and send your first authenticated request in under a minute.
The fastest way to test your proxy credentials from the shell.
Drop-in examples for `requests`, `httpx`, and `aiohttp`.
Use Roundproxies with `axios`, `fetch`, or `got`.
Browse our Help Center or email [team@roundproxies.com](mailto:team@roundproxies.com) — we usually reply within a few hours.
# Authentication
Source: https://docs.roundproxies.com/isp/authentication
Authenticate with ISP Proxies using username/password or IP whitelisting.
ISP proxies support two ways to authenticate. Pick whichever fits your setup — both can be active at the same time.
## Username & Password
The default method, and the one that works everywhere. Your credentials are included in every request:
```text theme={null}
http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}
```
You'll find your username and password in the [dashboard](https://app.roundproxies.com/dashboard/isp), and you can reset them there at any time. Resetting takes effect within a few minutes — update any running scripts before you rotate credentials, or they'll start failing with `407` errors.
Some tools (older browser extensions, certain game clients) can't handle proxy credentials. If yours is one of them, use IP whitelisting instead.
## IP Whitelisting
Instead of sending credentials, you register the IP of the machine that will use the proxies. Requests coming from a whitelisted IP go through without a username or password:
```text theme={null}
http://{PROXY_IP}:{PORT}
```
To set it up:
1. Find your server's public IP (for example via [api.ipify.org](https://api.ipify.org))
2. Add it under **IP Whitelist** in the [dashboard](https://app.roundproxies.com/dashboard/isp)
3. Wait a minute or two for the change to propagate, then test a request
Keep in mind:
* Whitelisting only helps if your machine has a **static** IP. If your ISP rotates your IP, requests will start failing with `407` until you update the whitelist.
* You can whitelist multiple IPs, e.g. your production server and your office.
* Remove IPs you no longer use — anyone on a whitelisted IP can use your proxies.
## Troubleshooting
| Problem | Likely cause | Fix |
| ----------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `407 Proxy Authentication Required` | Wrong credentials, or your IP isn't whitelisted. | Double-check credentials in the dashboard; confirm your current public IP matches the whitelist. |
| Works locally but not on the server | The server's IP isn't whitelisted. | Whitelist the server's public IP, or use username/password on the server. |
| Worked yesterday, fails today | Your ISP changed your IP, or credentials were reset. | Re-check your public IP and the whitelist; confirm credentials are current. |
Still stuck? See [Error Handling](/isp/error-handling) or email [team@roundproxies.com](mailto:team@roundproxies.com).
# Basics
Source: https://docs.roundproxies.com/isp/basics
How our ISP Proxies (static residential) work and how to set them up.
ISP proxies sit between our two other proxy types: the IPs are registered with real internet providers, so target sites see them as home connections, but they're hosted on datacenter hardware, so you get datacenter speed and uptime. They're also called static residential proxies — you get dedicated IPs that don't rotate, with unlimited bandwidth.
This is a developer guide: For easy and fast proxy creation head over to your ISP dashboard and create proxies there. Here is the dashboard link: [https://app.roundproxies.com/dashboard/isp](https://app.roundproxies.com/dashboard/isp)
## When to use them
Pick ISP proxies when you need one IP to stay the same *and* look residential:
* Managing accounts that flag logins from changing or datacenter IPs
* Checkout and purchase flows on protected shops (sneaker sites, ticketing)
* Long scraping sessions against targets that block datacenter IPs
* Anything where a rotating residential IP would log you out mid-session
Rule of thumb across the three products: [datacenter](/datacenter/basics) for speed on easy targets, [residential](/residentials/basics) for rotation across a huge pool, ISP for a stable IP that passes as residential.
## Proxy Format
Like datacenter proxies, ISP proxies are dedicated — the dashboard gives you a fixed list of IPs in this format:
```text theme={null}
IP:PORT:USERNAME:PASSWORD
```
### Components Breakdown
| Component | Description | Example |
| ------------ | ------------------------------------ | --------------- |
| **IP** | Your dedicated static residential IP | `198.51.100.7` |
| **Port** | Connection port | `8000` |
| **Username** | Your proxy username | `YOUR_USERNAME` |
| **Password** | Authentication password | `YOUR_PASSWORD` |
There's no session parameter and no rotation — the IP is yours and stays the same for the length of your plan.
## Authentication
Username/password and IP whitelisting both work. See [Authentication](/isp/authentication) for setup details.
## Example Request
```python Python theme={null}
import requests
proxies = {
'http': 'http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}',
'https': 'http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}'
}
response = requests.get('https://api.ipify.org?format=json', proxies=proxies)
print(response.json())
```
```bash cURL theme={null}
curl -x "http://{USERNAME}:{PASSWORD}@{PROXY_IP}:{PORT}" \
https://api.ipify.org?format=json
```
The response should return your proxy's IP, confirming the connection works.
## Tips
* Stick to one IP per account when doing account management — that's the whole point of a static IP.
* Bandwidth is unlimited, but target sites still rate-limit individual IPs. Spread heavy scraping across several IPs.
* If an IP gets banned by a target, replace it from the dashboard. Since ISP IPs look residential, bans are rarer than on datacenter IPs but not impossible.
* Something not working? Check [Error Handling](/isp/error-handling) for common errors and fixes.
# Error Handling
Source: https://docs.roundproxies.com/isp/error-handling
Common errors you may encounter when using ISP Proxies and how to resolve them.
When using Roundproxies ISP proxies, you may run into errors from the proxy network or the target site. The tables below summarize the most common ones, what they mean, and how to fix them.
## Authentication Errors
| Error | Meaning | Fix |
| ----------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `407 Proxy Authentication Required` | Credentials missing, malformed, or incorrect. | Verify credentials in the [dashboard](https://app.roundproxies.com/dashboard/isp). If using IP whitelisting, confirm your current IP is added. See [Authentication](/isp/authentication). |
| `401 Unauthorized` | Account recognized but request not allowed. | Confirm your subscription is active and your plan includes the requested ISP proxies. |
## Connection Errors
| Error | Meaning | Fix |
| ------------------------------ | ------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `Connection Timed Out` | The proxy didn't respond in time. | Retry the request. If one specific IP keeps timing out, replace it from the dashboard. |
| `Connection Refused` / `Reset` | Connection rejected or dropped mid-request. | Check firewall/outbound rules and confirm you're using the correct port from your proxy list. |
## IP Errors
| Error | Meaning | Fix |
| ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IP Banned by Target` | The destination site has blocked your static IP. | Replace the IP from the dashboard. This is rarer than with datacenter IPs since ISP IPs look residential, but heavy use on one target can still trigger it. |
| `Static IP Unavailable` | Your dedicated IP is offline or being replaced. | Wait a few minutes and retry — replacements happen automatically. Contact support if it persists. |
## HTTP Status Errors From the Target Site
These come from the destination website, not the proxy itself.
| Error | Meaning | Fix |
| ----------------------- | ------------------------------------- | ------------------------------------------------------------------------------- |
| `403 Forbidden` | Site is blocking the request. | Slow down, vary your request patterns, or spread the load across more IPs. |
| `429 Too Many Requests` | Site is rate-limiting your IP. | Reduce the request rate — a static IP can't rotate its way out of a rate limit. |
| `5xx` | Server-side error on the target site. | Retry with exponential backoff. |
## Quota / Billing Errors
| Error | Meaning | Fix |
| -------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `Plan Expired` | Your ISP proxy plan has ended. | Renew the plan in the [dashboard](https://app.roundproxies.com) — your IPs are held for a grace period before being released. |
## Still stuck?
Reach out at [team@roundproxies.com](mailto:team@roundproxies.com) or visit the [Help Center](https://help.roundproxies.com/en).
# Reseller Access
Source: https://docs.roundproxies.com/reseller
Resell Roundproxies products under your own brand.
We offer reseller access to all our products — residential, ISP, and datacenter proxies. As a reseller you buy at volume rates and resell to your own customers.
Reseller access is granted on top of an existing Roundproxies account. [Sign up](https://app.roundproxies.com) first, then reach out to [team@roundproxies.com](mailto:team@roundproxies.com) from that account's email with a short description of your use case and expected volume.
## What you can resell
A GB pool you mint **sub-users** against — gateway accounts with their own traffic limit that you hand to your customers. GB are consumed and never come back.
Datacenter (shared IPs) and ISP (dedicated IPs). You hold a **concurrent capacity limit** and draw allocations of IPs against it, releasing them when a customer churns.
There are no orders, balances, or per-package billing in the API. Residential data is drawn from your own purchases; static proxies are drawn from a capacity limit we set for you.
## Reseller API
Approved resellers get an API for automating everything the reseller dashboard does: checking your pool, creating sub-user accounts for your customers, topping them up, allocating static proxies, and pulling usage history.
The full reference starts at [Reseller API → Basics](/reseller/basics). Your reseller key is shown once when your account is set up — and if you're logged into the dashboard, you can also call the API with your normal session token, so a lost key never locks you out.
# Authentication
Source: https://docs.roundproxies.com/reseller/authentication
Authenticate with the Reseller API using your reseller key or your dashboard session.
Reseller endpoints accept two credentials:
| Credential | Header | Use it for |
| --------------- | ----------------------------- | --------------------------------------------------------------- |
| Reseller key | `x-reseller-key: rsl_...` | Programmatic integrations, servers, scripts |
| Dashboard token | `Authorization: Bearer ` | Calls made as the logged-in user linked to the reseller account |
If both are present, the reseller key wins.
```bash cURL theme={null}
curl https://api.roundproxies.com/reseller/account \
-H "x-reseller-key: rsl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
Note that `x-reseller-key` is a different header from the one used by the [residential usage API](/residentials/basics), which uses `x-api-key`. The reseller key is scoped to your reseller account and its pool.
Because the dashboard token works too, a logged-in user with reseller access needs no API key at all. The key exists for integrations that run without a user session.
## Keeping your key safe
Your reseller key can spend your data allocation and your proxy capacity. Treat it like a password: keep it server-side, and never put it in client-side code, URLs, or logs.
Your key is shown **once**, when it's issued. Only a SHA-256 hash of it is stored, so there is no way to read it back later — not by you, and not by support.
## Checking your access
### GET /reseller/self
Authenticated with your **dashboard token**, not the reseller key. Tells you whether the logged-in user has reseller access.
```bash cURL theme={null}
curl https://api.roundproxies.com/reseller/self \
-H "Authorization: Bearer $JWT"
```
```json theme={null}
{
"hasResellerAccess": true,
"isActive": true,
"account": { "...": "..." }
}
```
## Rotating your key
### POST /reseller/self/rotate-key
Also authenticated with your dashboard token, so it works **even when the key is lost**. The new key is returned once, in the response body.
```bash cURL theme={null}
curl -X POST https://api.roundproxies.com/reseller/self/rotate-key \
-H "Authorization: Bearer $JWT"
```
| Status | Meaning |
| ------ | --------------------------------- |
| `404` | This user has no reseller access |
| `403` | The reseller account is suspended |
The same rotation is available from your dashboard under **Reseller → Rotate key**.
Rotation is immediate and unforgiving:
* The old key stops working the moment the new one is issued. There's no grace period.
* The new key is shown once, same as the original.
* Any running integration still sending the old key starts failing with `401 Invalid reseller API key`.
Deploy the new key everywhere before you rotate, or expect a gap.
Rotating your key does not affect your sub-users or proxy allocations. Those credentials are independent and keep working.
## Suspension
A suspended reseller account (`isActive: false`) gets `401` on **every** reseller endpoint. Existing sub-users keep working upstream until their data runs out, so your customers aren't cut off immediately.
## Troubleshooting
| Problem | Likely cause | Fix |
| ----------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `401 Invalid reseller API key` | Wrong key, or the key was rotated. | Check the key in use against `apiKeyPrefix` from [`GET /reseller/account`](/reseller/basics#your-account); rotate and redeploy if lost. |
| `401 Reseller account is suspended` | Your reseller account is on hold. | Contact support. Existing sub-users keep working until their data runs out. |
| `404` on `/reseller/self` | The logged-in user has no reseller access. | Request access from [team@roundproxies.com](mailto:team@roundproxies.com). |
| Worked yesterday, fails today | Someone rotated the key. | Rotate again via `POST /reseller/self/rotate-key` or the dashboard, and redeploy. |
See [Error Handling](/reseller/error-handling) for the full error reference.
# Basics
Source: https://docs.roundproxies.com/reseller/basics
How the Roundproxies Reseller API works and how to check your pool.
The Reseller API covers two product lines:
* **Residential data** — a pool of GB, measured against your own residential purchases. You spend it by creating **sub-users**: username/password accounts on our residential gateway, each with its own traffic limit, which you hand to your customers.
* **Static proxies** — datacenter (shared IPs) and ISP (dedicated IPs). You hold a concurrent capacity limit per product and draw **allocations** of IPs against it.
Your customers never need to touch this API. They just use the proxy credentials you give them.
| | |
| ------------ | ------------------------------ |
| **Base URL** | `https://api.roundproxies.com` |
| **Format** | JSON in, JSON out |
Send `Content-Type: application/json` on every request that has a body.
Everything below can also be done from your reseller dashboard. The API exists so you can automate it from your own systems.
## Where your data pool comes from
Your residential allocation is **self-funding**: it is your own purchased residential data, plus any optional top-ups we grant you.
```text theme={null}
allocatedBytes = purchasedBytes + grantedBytes
remainingBytes = allocatedBytes − assignedBytes
```
* `purchasedBytes` — residential data you bought through the dashboard like any other customer. Kept in sync automatically; buy more and your reseller allocation grows with it.
* `grantedBytes` — optional manual top-ups from us (compensation, negotiated bonuses). Not required for the pool to work.
The pool is **tracked, not enforced**. Creating a sub-user never fails for lack of data — `remainingBytes` simply goes negative, recording how far ahead of your purchases you've assigned. There is no "not enough data" error.
A negative `remainingBytes` is your signal to buy more residential data. It is a bookkeeping figure, not a block — monitor it yourself.
## Units
The API is asymmetric about units, and it's the most common thing to get wrong:
* Every data figure in **responses** is in **bytes** (`dataBytes`, `remainingBytes`, `rawUsed`).
* Every data figure you **send** is in whole **GB**, where 1 GB = 1024³ bytes (`1,073,741,824`).
```js theme={null}
const BYTES_PER_GB = 1024 ** 3;
const toGB = (bytes) => (bytes / BYTES_PER_GB).toFixed(2);
```
Format displayed values from the raw byte fields with the 1024³ divisor, so a 2 GB account displays as "2.00 GB".
## Your account
### GET /reseller/account
Returns your pool, where it came from, and your static proxy capacity.
```bash cURL theme={null}
curl https://api.roundproxies.com/reseller/account \
-H "x-reseller-key: $KEY"
```
**200 OK**
```json theme={null}
{
"account": {
"id": "...",
"name": "Acme",
"email": "acme@example.com",
"apiKeyPrefix": "rsl_a1b2c3d4",
"data": {
"allocatedBytes": 107374182400,
"remainingBytes": 64424509440,
"assignedBytes": 42949672960,
"purchasedBytes": 96636764160,
"grantedBytes": 10737418240
},
"proxies": {
"datacenter": { "limit": 100, "used": 13 },
"isp": { "limit": 20, "used": 0 }
},
"createdAt": "..."
},
"subUserCount": 8
}
```
### Response Fields
| Field | Type | Description |
| ------------------------- | ------ | -------------------------------------------------------------------------- |
| `account.apiKeyPrefix` | string | The visible prefix of your active key, for identifying which key is in use |
| `data.allocatedBytes` | number | `purchasedBytes + grantedBytes` |
| `data.purchasedBytes` | number | Your own residential-data purchases |
| `data.grantedBytes` | number | Manual top-ups granted to you |
| `data.assignedBytes` | number | Data currently assigned to sub-users |
| `data.remainingBytes` | number | `allocated − assigned`. **Signed** — goes negative when you over-assign |
| `proxies..limit` | number | Concurrent IPs you may hold for `datacenter` / `isp` |
| `proxies..used` | number | IPs currently held in active allocations |
| `subUserCount` | number | How many sub-users you've created |
To increase your allocation, buy residential data from your dashboard. To raise your static proxy capacity, contact your account manager.
### Live usage
Add `includeUsage=true` to fold in live consumption counters from the gateway:
```bash cURL theme={null}
curl "https://api.roundproxies.com/reseller/account?includeUsage=true" \
-H "x-reseller-key: $KEY"
```
```json theme={null}
{
"usage": { "rawUsed": 1288490188, "rawTotal": 6442450944, "failedLookups": 0 },
"retailUsage": { "rawUsed": 0, "rawTotal": 5368709120 }
}
```
| Field | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `usage` | Consumption summed across **all** your sub-users |
| `usage.failedLookups` | Sub-users whose gateway lookup failed. Their usage is **excluded** from the sums — treat any non-zero value as a partial total |
| `retailUsage` | Live counters for your **own** residential package (the source of the pool), kept separate so each used/total pair stays a sane ratio |
`retailUsage` is `null` when the account has no retail package, or when its gateway lookup failed. Treat `null` as "unavailable", never as zero.
`includeUsage=true` performs one gateway lookup per sub-user (batched), so it's noticeably slower. Without the flag the endpoint makes no gateway calls at all. For trends over time use [Usage History](/reseller/usage-history) instead — it's served from stored history and costs nothing.
## Next steps
* [Authentication](/reseller/authentication) — your API key, dashboard-token access, and rotation
* [Sub-Users](/reseller/sub-users) — create, list, adjust, and delete customer accounts
* [Static Proxies](/reseller/static-proxies) — allocate and release datacenter and ISP IPs
* [Usage History](/reseller/usage-history) — consumption time series
* [Proxy Access](/reseller/proxy-access) — the gateway format your customers connect with
* [Error Handling](/reseller/error-handling) — error reference and retry behavior
# Error Handling
Source: https://docs.roundproxies.com/reseller/error-handling
Error reference, retry behavior, and operational notes for the Reseller API.
## Error reference
| Status | Where | Example message | What to do |
| ------ | ------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `400` | anywhere | Validation errors — `message` is an array of strings | Fix the request body |
| `400` | `POST /reseller/users/:username/data` | Removing more data than is assigned, or a zero delta | Adjust the delta; assignments can't go below zero |
| `400` | `POST /reseller/proxies` | Not enough capacity, or not enough IPs in a region | Release an allocation, request fewer IPs, or ask for a higher limit |
| `400` | `DELETE /reseller/proxies/:id` | Allocation already released | Nothing to do |
| `400` | usage history | Requested range exceeds the cap for that granularity | Narrow the range or use a coarser granularity |
| `401` | reseller endpoints | `Invalid reseller API key` | Check the key; rotate it via [`POST /reseller/self/rotate-key`](/reseller/authentication#rotating-your-key) |
| `401` | reseller endpoints | `Reseller account is suspended` | Contact support |
| `403` | `POST /reseller/self/rotate-key` | The reseller account is suspended | Contact support |
| `404` | `GET /reseller/self` | The logged-in user has no reseller access | Request access |
| `404` | sub-user endpoints | `Sub-user "x" not found` | Check the username — you can only see your own sub-users |
| `409` | `POST /reseller/users` | `Username "x" is already taken. Pick another one.` | Choose a different username |
| `502` | anywhere | `... Nothing was charged — please retry.` | Retry — the operation is atomic |
On validation failures the `message` field is an **array** of strings, not a single string. Handle both shapes when parsing errors.
### There is no "not enough data" error
The residential pool is [tracked, not enforced](/reseller/basics#where-your-data-pool-comes-from). Creating or topping up a sub-user never fails for lack of data — `remainingBytes` just goes negative. Watch that figure yourself and buy more residential data when it crosses zero.
Static proxy capacity is the opposite: it **is** enforced, and over-drawing returns `400` with nothing assigned.
## Retries
`502` responses are always safe to retry. Sub-user creation, data adjustments, deletion, and proxy allocation are atomic: on any failure, nothing is charged and nothing is left half-created.
* A `502` on `POST /reseller/users` means no account was created and no data was debited.
* A `502` on `DELETE /reseller/users/:username` means the sub-user is untouched — credentials still work, nothing was refunded.
* A `502` on `POST /reseller/proxies` means no IPs were assigned and no capacity was taken.
Other statuses are not transient — retrying a `400`, `404`, or `409` with the same body returns the same error.
## Suspended accounts
If every call starts returning `401 Reseller account is suspended`, contact support. Your existing sub-users keep working upstream until their data runs out, so your customers aren't cut off immediately, but you can't create, adjust, or allocate anything while suspended.
## Sub-user lifecycle
Sub-users can be [deleted](/reseller/sub-users#deleting-a-sub-user), and unconsumed data comes back to your pool — both on deletion and on a negative data adjustment. Data your customer already **consumed** is gone for good.
Deletion is irreversible and drains the upstream account first. To restore access for a customer, create a new sub-user with a fresh username.
## Usage etiquette
Live usage lookups hit the gateway. Fetch them when you actually need them — page loads, billing runs — rather than in tight polling loops:
* `includeUsage=true` on [`GET /reseller/users`](/reseller/sub-users#listing-your-sub-users) costs one gateway lookup per row.
* `includeUsage=true` on [`GET /reseller/account`](/reseller/basics#live-usage) costs one per sub-user.
* `live=true` on [usage history](/reseller/usage-history#real-time-totals) costs one per account in scope.
Without those flags, [usage history](/reseller/usage-history) is served from stored data and makes no gateway calls at all — use it for dashboards and trends.
Questions? Contact your Roundproxies account manager or email [team@roundproxies.com](mailto:team@roundproxies.com).
# Proxy Access
Source: https://docs.roundproxies.com/reseller/proxy-access
How your customers connect with the credentials you issue them.
Your customers connect with the credentials you issued them. They don't need an API key, and they don't call the Reseller API at all.
Proxy strings are built client-side — there's no endpoint that returns a formatted proxy line for a sub-user. You format the credentials against the gateway yourself.
## Residential sub-users
```text theme={null}
residential.roundproxies.com:5000
```
HTTP, with sticky sessions.
### Username format
Targeting is encoded in the proxy **username**:
```text theme={null}
client--country--session-
```
| Component | Description |
| ------------- | ------------------------------------------------- |
| `client-` | Fixed prefix |
| `` | The sub-user's username from the API |
| `` | The full country name, e.g. `Germany` |
| `` | Any random string, e.g. 8 alphanumeric characters |
The sub-user's **password is sent unmodified** — only the username gets the targeting prefix.
Contact support for the full list of supported country names, and for rotating (non-sticky) sessions or custom session durations — those aren't part of the confirmed format above.
### Sessions
The same session id keeps the same exit IP. To get a new IP, use a new session id. Generate one session id per concurrent connection you want.
### Full proxy line
In `host:port:username:password` form:
```text theme={null}
residential.roundproxies.com:5000:client-acme_customer1-country-Germany-session-x7k2m9pq:THE_PASSWORD
```
### Testing a connection
```bash cURL theme={null}
curl -x "http://client-acme_customer1-country-Germany-session-x7k2m9pq:THE_PASSWORD@residential.roundproxies.com:5000" \
https://ipinfo.io/json
```
```python Python theme={null}
import requests
proxy = (
"http://client-acme_customer1-country-Germany-session-x7k2m9pq"
":THE_PASSWORD@residential.roundproxies.com:5000"
)
response = requests.get(
"https://ipinfo.io/json",
proxies={"http": proxy, "https": proxy},
)
print(response.json())
```
You should see a residential IP in the requested country.
### Metering
Traffic is metered against the sub-user's data limit and shows up on the [usage endpoints](/reseller/sub-users#checking-one-sub-user) within moments. Once `rawUsed` reaches `rawTotal`, the account stops working until you top it up.
## Static proxies
[Datacenter and ISP allocations](/reseller/static-proxies) need no formatting. Each IP comes back from the API with everything your customer needs:
```json theme={null}
{ "ip": "1.2.3.4", "port": 8080, "username": "a1b2c3", "password": "d4e5f6", "region": "US" }
```
```text theme={null}
1.2.3.4:8080:a1b2c3:d4e5f6
```
There's no targeting prefix — the region is fixed when the IP is allocated — and no data limit, so nothing meters down. The IPs work until you release the allocation.
# Static Proxies
Source: https://docs.roundproxies.com/reseller/static-proxies
Allocate and release datacenter and ISP IPs against your concurrent capacity.
Alongside residential data you can resell **static proxies**:
| `productType` | What it is |
| ------------- | ------------- |
| `datacenter` | Shared IPs |
| `isp` | Dedicated IPs |
These work differently from residential data. Instead of a consumable GB pool, you hold a **concurrent capacity limit** per product — "may hold 100 datacenter + 20 ISP IPs at once". You draw an **allocation** (a batch of IPs for one end customer) against that limit, and release it when the customer churns. Released IPs free the capacity again.
## Your capacity
[`GET /reseller/account`](/reseller/basics#your-account) reports it:
```json theme={null}
"proxies": {
"datacenter": { "limit": 100, "used": 13 },
"isp": { "limit": 20, "used": 0 }
}
```
`used` counts IPs in **active** allocations. To raise a limit, contact your account manager.
Available regions and their stock are discoverable from the public `GET /region/availability?type=...` endpoint.
## Allocating proxies
### POST /reseller/proxies
Draws a batch of IPs for one end customer. Credentials are generated per IP.
```bash cURL theme={null}
curl -X POST https://api.roundproxies.com/reseller/proxies \
-H "x-reseller-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"productType": "datacenter", "regions": {"US": 5, "DE": 2}, "note": "customer #123"}'
```
### Request Fields
| Field | Required | Rules |
| ------------- | -------- | -------------------------------------------------------------- |
| `productType` | yes | `datacenter` or `isp` |
| `regions` | yes | Map of region name → IP count. Max **1000** IPs per allocation |
| `note` | no | Free-text label, e.g. which customer this batch is for |
**200 OK**
```json theme={null}
{
"message": "Proxies allocated",
"allocation": {
"id": "...",
"productType": "datacenter",
"regions": { "US": 5, "DE": 2 },
"ipCount": 7,
"status": "active",
"note": "customer #123",
"createdAt": "..."
},
"proxies": [
{ "ip": "1.2.3.4", "port": 8080, "username": "a1b2c3", "password": "d4e5f6", "region": "US" }
],
"capacity": {
"datacenter": { "limit": 100, "used": 20 },
"isp": { "limit": 20, "used": 0 }
}
}
```
### Errors
| Status | Meaning |
| ------ | ------------------------------------------------------------------------------------------------ |
| `400` | Not enough capacity, or not enough IPs available in a requested region. **Nothing is assigned.** |
| `502` | Allocation failed upstream. **Nothing is assigned — retry safely.** |
Unlike the residential pool, static proxy capacity **is** enforced. Check `limit` against `used` before requesting a large batch.
## Listing allocations
### GET /reseller/proxies
Paginated list of your allocations. Accepts `page` and `limit`. Proxy lists are omitted here — fetch one allocation for those.
```bash cURL theme={null}
curl "https://api.roundproxies.com/reseller/proxies?page=1&limit=25" \
-H "x-reseller-key: $KEY"
```
## One allocation, with credentials
### GET /reseller/proxies/:id
Allocation detail **plus** the full `ip:port:username:password` list.
```bash cURL theme={null}
curl https://api.roundproxies.com/reseller/proxies/ALLOCATION_ID \
-H "x-reseller-key: $KEY"
```
Released allocations still return, with an empty `proxies` array.
## Releasing an allocation
### DELETE /reseller/proxies/:id
Tears down all the allocation's IPs upstream and returns the capacity to your pool.
```bash cURL theme={null}
curl -X DELETE https://api.roundproxies.com/reseller/proxies/ALLOCATION_ID \
-H "x-reseller-key: $KEY"
```
Returns `400` if the allocation is already released.
Releasing kills the credentials for every IP in the batch. Your customer loses access immediately, and re-allocating gives them different IPs.
# Sub-Users
Source: https://docs.roundproxies.com/reseller/sub-users
Create, list, adjust, and delete the gateway accounts you hand to your customers.
A sub-user is a gateway account belonging to one of your customers: a username, a password, and a data limit drawn from your pool. Creating one debits your unassigned data immediately.
## Creating a sub-user
### POST /reseller/users
```bash cURL theme={null}
curl -X POST https://api.roundproxies.com/reseller/users \
-H "x-reseller-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"dataGB": 5, "username": "acme_customer1"}'
```
### Request Fields
| Field | Required | Rules |
| ---------- | -------- | ---------------------------------------------------------------------------------------------- |
| `dataGB` | yes | Whole GB, 1–10,000 |
| `username` | no | 6–32 chars, lowercase `a-z 0-9 _ -`. Auto-generated if omitted. Usernames are globally unique. |
| `password` | no | 8–64 chars, `a-z A-Z 0-9 _ -`. Auto-generated if omitted. |
**200 OK**
```json theme={null}
{
"message": "Sub-user created",
"subUser": {
"username": "acme_customer1",
"password": "9f8e7d6c5b4a...",
"dataBytes": 5368709120,
"dataGB": 5,
"createdAt": "..."
},
"remainingBytes": 59055800320
}
```
Credentials stay retrievable from the list and detail endpoints. This is not a one-time reveal, so you don't have to store the password yourself.
### Errors
| Status | Meaning |
| ------ | ------------------------------------------------------------------------- |
| `409` | Username already taken — pick another. |
| `502` | The gateway rejected the account. **Nothing was charged — retry safely.** |
There is no "not enough data" error. The pool is [tracked, not enforced](/reseller/basics#where-your-data-pool-comes-from) — assigning more than you've purchased just drives `remainingBytes` negative.
## Listing your sub-users
### GET /reseller/users
Paginated, with stored credentials and assigned totals. Accepts `page` and `limit` (default `25`, max `100`).
```bash cURL theme={null}
curl "https://api.roundproxies.com/reseller/users?page=1&limit=25" \
-H "x-reseller-key: $KEY"
```
Add `includeUsage=true` to include each sub-user's **live consumption** from the gateway. This costs one gateway lookup per row, so the request gets slower as the page grows — use it for dashboard views, not high-frequency polling.
**200 OK**
```json theme={null}
{
"subUsers": [
{
"username": "acme_customer1",
"password": "...",
"dataBytes": 5368709120,
"dataGB": 5,
"createdAt": "...",
"usage": {
"used": "1.2 GB",
"total": "5 GB",
"rawUsed": 1288490188,
"rawTotal": 5368709120
}
}
],
"total": 8,
"page": 1,
"limit": 25
}
```
If a live lookup fails for one row, that row comes back with `"usage": null` and a `usageError` note rather than failing the whole request. Handle `null` usage as "unknown", not as zero.
## Checking one sub-user
### GET /reseller/users/:username
A single sub-user with live usage — this is the endpoint for "how much data has this customer consumed?"
```bash cURL theme={null}
curl https://api.roundproxies.com/reseller/users/acme_customer1 \
-H "x-reseller-key: $KEY"
```
**200 OK**
```json theme={null}
{
"subUser": {
"username": "acme_customer1",
"password": "...",
"dataBytes": 5368709120,
"dataGB": 5
},
"usage": {
"used": "1.2 GB",
"total": "5 GB",
"rawUsed": 1288490188,
"rawTotal": 5368709120
}
}
```
If the gateway is unreachable the credentials still return, with `"usage": null` and a `usageError` note.
When `rawUsed >= rawTotal` the account is exhausted and stops working. Top it up to reactivate it.
## Adjusting a sub-user's data
### POST /reseller/users/:username/data
Takes a **signed** GB delta. Positive tops up, negative takes unconsumed data back.
```bash cURL theme={null}
curl -X POST https://api.roundproxies.com/reseller/users/acme_customer1/data \
-H "x-reseller-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"dataGB": 10}'
```
| Direction | Effect |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `{"dataGB": 10}` | Debits your unassigned allocation and extends the account upstream |
| `{"dataGB": -3}` | Reduces the assignment, shrinks the upstream quota by the same amount, and returns the bytes to your unassigned allocation |
Rules:
* Range is ±10,000 GB. Zero is rejected.
* An assignment can never go below zero — removing more than is currently assigned is a `400`.
* Removal only reclaims **unconsumed** data. Data your customer already used is gone.
**200 OK**
```json theme={null}
{
"message": "Added 10GB",
"username": "acme_customer1",
"dataBytes": 16106127360,
"remainingBytes": 42949672960
}
```
A `502` means nothing was charged and a retry is safe.
## Deleting a sub-user
### DELETE /reseller/users/:username
Ends a customer's access and reclaims what they didn't use.
```bash cURL theme={null}
curl -X DELETE https://api.roundproxies.com/reseller/users/acme_customer1 \
-H "x-reseller-key: $KEY"
```
**200 OK**
```json theme={null}
{
"username": "acme_customer1",
"refundedBytes": 4080218931,
"refundedGB": 3.8
}
```
What happens, in order:
1. The account's unconsumed quota is drained upstream — the credentials stop working.
2. The unconsumed portion is refunded to your unassigned allocation.
3. The record is removed from your account.
Consumption history for your account is preserved, so deleting a sub-user doesn't erase it from your [usage history](/reseller/usage-history).
Deletion is irreversible. To give the same customer access again, create a new sub-user — and prefer a fresh username, since the old account still exists upstream in a drained state.
If the gateway cannot be reached, the deletion aborts with a `502` and **nothing changes** — retry later.
# Usage History
Source: https://docs.roundproxies.com/reseller/usage-history
Consumption time series for your pool and for individual sub-users.
Where `includeUsage=true` gives you a live snapshot, these endpoints give you consumption **over time** as a zero-filled time series.
| Endpoint | Scope |
| --------------------------------------------- | -------------------------------------------------------------- |
| `GET /reseller/usage-history` | Pool-wide — your own retail account plus all sub-users, summed |
| `GET /reseller/users/:username/usage-history` | One sub-user |
Both are served entirely from stored history and make **no gateway calls**, so they're fast and safe to call freely.
```bash cURL theme={null}
curl "https://api.roundproxies.com/reseller/usage-history?granularity=day" \
-H "x-reseller-key: $KEY"
```
**200 OK**
```json theme={null}
{
"granularity": "day",
"from": "2026-07-16T00:00:00.000Z",
"to": "2026-08-15T00:00:00.000Z",
"totalBytes": 5801,
"series": [
{ "start": "2026-08-14T00:00:00.000Z", "usedBytes": 5801 },
{ "start": "2026-08-15T00:00:00.000Z", "usedBytes": 0 }
]
}
```
Every bucket in the range is present, including empty ones. Weeks start Monday, UTC.
## Query parameters
| Parameter | Description |
| ------------- | ------------------------------------------------------------------------ |
| `granularity` | `hour`, `day` (default), `week`, `month`, or `year` |
| `from` / `to` | ISO 8601 timestamps. Defaults and caps depend on granularity |
| `live` | `true` folds consumption since the last snapshot into the current bucket |
### Defaults and range caps
| Granularity | Default range |
| ----------- | -------------- |
| `hour` | Last 48 hours |
| `day` | Last 30 days |
| `week` | Last 12 weeks |
| `month` | Last 12 months |
| `year` | Last 5 years |
Each granularity has a maximum range. Asking for more returns `400` — narrow the range or use a coarser granularity.
### Real-time totals
Stored history can be up to 15 minutes behind. Pass `live=true` to read the gateway counters at request time and fold the delta into the current bucket:
```bash cURL theme={null}
curl "https://api.roundproxies.com/reseller/usage-history?granularity=hour&live=true" \
-H "x-reseller-key: $KEY"
```
The response then carries `"live": true` and a `liveFailedLookups` count.
`live=true` costs one gateway call per account in scope — your retail account plus every sub-user, the same cost as `includeUsage`. It's skipped automatically for ranges that don't reach the present, so historical queries stay cheap.
## How the data is produced
* A cron snapshots every gateway account's cumulative counters **every 15 minutes**. `hour` series build on these, so they lag up to 15 minutes, and snapshots are retained for **90 days**.
* A daily rollup at **00:20 UTC** condenses each UTC day into one document per account, kept **forever**. `day`, `week`, `month`, and `year` build on these.
* The current, not-yet-rolled-up day is blended in live from snapshots, so "today" is never an empty bucket.
* Counter resets — for example an account recreated upstream — are clamped. A bucket is never negative.
History begins when this feature was deployed. There is no retroactive backfill, so ranges reaching further back will show empty buckets.
Deleting a sub-user does not erase its contribution: consumption history for your account is preserved.
# ASN-Targeting
Source: https://docs.roundproxies.com/residentials/asn-targeting
Route residential traffic through a specific Autonomous System Number (ASN).
ASN-targeting routes requests through residential IPs that belong to a specific Autonomous System — typically a single ISP or carrier. This is useful when a target site treats traffic differently based on the network operator (for example, mobile carriers vs. consumer broadband ISPs).
ASNs are 32-bit identifiers assigned by IANA/RIRs to networks that announce routes on the public internet. Each major ISP, mobile carrier, and hosting provider has one or more ASNs.
## Targeting Format
Add the `asn` parameter to your proxy username:
```
client-{CLIENT_ID}-asn-{ASN_NUMBER}-session-{SESSION_ID}
```
Numeric ASN of the network you want to route through. Use the number only — do not include the `AS` prefix.
| Parameter | Description | Example |
| --------- | --------------------------------------- | ---------- |
| `asn` | Numeric ASN identifier (no `AS` prefix) | `asn-3320` |
## Combining With Geo-Targeting
ASN-targeting can be combined with `country` to narrow the pool to IPs from a specific ISP within a single country:
```
client-{CLIENT_ID}-country-Germany-asn-3320-session-{SESSION_ID}
```
State and city can be added on top, but the available IP pool shrinks quickly — start broad and refine only if needed.
## Example Request
```python Python theme={null}
import requests
proxies = {
'http': 'http://client-{CLIENT_ID}-country-Germany-asn-3320-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000',
'https': 'http://client-{CLIENT_ID}-country-Germany-asn-3320-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000'
}
response = requests.get('https://api.ipify.org?format=json', proxies=proxies)
print(response.json())
```
```bash cURL theme={null}
curl -x "http://client-{CLIENT_ID}-country-Germany-asn-3320-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000" \
https://api.ipify.org?format=json
```
## Finding an ASN
You can look up the ASN of any IP or ISP using public tools:
* [bgp.he.net](https://bgp.he.net) — search by ISP name or IP
* [ipinfo.io](https://ipinfo.io) — returns ASN alongside IP metadata
* `whois ` from the command line
Common examples:
| ISP | ASN |
| ---------------------------- | ------ |
| Deutsche Telekom (Germany) | `3320` |
| Comcast (US) | `7922` |
| Vodafone (UK) | `5378` |
| Bezeq International (Israel) | `8551` |
## Troubleshooting
* **`PX1002`** (`502`, no exit node available) — the requested ASN has no live IPs at the moment, or it doesn't intersect with your `country`/`state` constraints. Drop the geo refinements or try a related ASN from the same carrier.
* **`PX1004`** (`400`, unsupported targeting option) — ensure the ASN is numeric only (e.g. `asn-3320`, not `asn-AS3320`).
* See [Error Handling](/residentials/error-handling) for the full list of proxy errors.
# Basics
Source: https://docs.roundproxies.com/residentials/basics
How our Residential Proxies work and how to set them up correctly.
Roundproxies residential proxies offer a global network of residential IPs with country, state, and city targeting, plus sessions for consistent IPs.
This is a developer guide: For easy and fast proxy creation head over to your Residential dashboard and create proxies there. Here is the dashboard link: [https://app.roundproxies.com/dashboard/residential](https://app.roundproxies.com/dashboard/residential)
## Proxy Structure
Our residential proxies follow a standardized format that allows precise geographic targeting and session control:
```text theme={null}
residential.roundproxies.com:5000:client-CLIENT_ID-TARGETING_PARAMS-session-SESSION_ID:PASSWORD
```
### Components Breakdown
| Component | Description | Example |
| ------------- | ------------------------------------- | --------------------------------------------------- |
| **Host** | Proxy server hostname | `residential.roundproxies.com` |
| **Port** | Connection port | `5000` |
| **Client ID** | Your unique client identifier | `client-{YOUR_CLIENT_NAME}` |
| **Targeting** | Geographic targeting parameters | `country-Israel-state-northerndistrict-city-maghar` |
| **Session** | Session identifier for IP persistence | `session-lw515ejc` |
| **Password** | Authentication password | `YOUR_PASSWORD` |
## Geographic Targeting
Keep in mind that you **only** need to have the country parameter for your proxies. Other parameters are optional and can be enabled on-demand. However, the more specific you chose the region the more the chance might be that the region has less proxies.
### Country Targeting
Country name of the country you would like to target.
Target specific countries by including the country parameter in your proxy credentials:
```text theme={null}
country-{COUNTRY_NAME}
```
**Available countries in examples:**
* Israel
* Hungary
* Germany
### State/Region Targeting
State name of the state (mathching the country) you would like to target.
Narrow down to specific states or regions:
```text theme={null}
state-{STATE_NAME}
```
**Examples:**
* `state-northerndistrict` (Israel)
* `state-pestcounty` (Hungary)
* `state-citystatebremen` (Germany)
* `state-landberlin` (Germany)
### City Targeting
City name that is supported and matches the state of the proxy.
Target specific cities for maximum precision:
```text theme={null}
city-{CITY_NAME}
```
**Examples:**
* `city-maghar` (Israel)
* `city-god` (Hungary)
* `city-bremen` (Germany)
* `city-berlin` (Germany)
# City-Targeting
Source: https://docs.roundproxies.com/residentials/city-targeting
Target residential IPs in a specific city for maximum geographic precision.
City-targeting routes requests through residential IPs located in a single city — the most precise level of geo-targeting we offer. Add the `city` parameter to the username segment of your proxy credentials, together with the matching `country` and `state`.
City is the narrowest targeting level, so it has the smallest IP pool. Always pair `city` with the correct `country` and `state` — a city that doesn't match its state returns no IPs.
## Targeting Format
Add the `city` parameter after `country` and `state`, before your session ID:
```
client-{CLIENT_ID}-country-{COUNTRY}-state-{STATE}-city-{CITY}-session-{SESSION_ID}
```
City name that matches the selected state. Lowercase, dash-separated, no spaces or special characters.
| Parameter | Required | Description |
| --------- | -------- | ----------------------------------- |
| `country` | Yes | Country the city belongs to |
| `state` | Yes | State or region the city belongs to |
| `city` | No | City within the state |
City names are written lowercase with spaces removed (e.g. `city-newyork`, `city-telaviv`).
## Examples
| City | Parameter | State | Country |
| ------ | ------------- | ------------------------ | ------- |
| Berlin | `city-berlin` | `state-landberlin` | Germany |
| Bremen | `city-bremen` | `state-citystatebremen` | Germany |
| Maghar | `city-maghar` | `state-northerndistrict` | Israel |
| Göd | `city-god` | `state-pestcounty` | Hungary |
## Example Request
```python Python theme={null}
import requests
proxies = {
'http': 'http://client-{CLIENT_ID}-country-Germany-state-landberlin-city-berlin-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000',
'https': 'http://client-{CLIENT_ID}-country-Germany-state-landberlin-city-berlin-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000'
}
response = requests.get('https://api.ipify.org?format=json', proxies=proxies)
print(response.json())
```
```bash cURL theme={null}
curl -x "http://client-{CLIENT_ID}-country-Germany-state-landberlin-city-berlin-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000" \
https://api.ipify.org?format=json
```
## Tips
* Only reach for city-targeting when your use case truly needs it — [country or state targeting](/residentials/geo-targeting) gives you a much larger IP pool.
* If you receive `PX1002` (no exit node available), drop the `city` parameter and retry with state-level targeting. See [Error Handling](/residentials/error-handling).
* Pair city-targeting with a sticky [session](/residentials/session) to keep the same exit IP across requests.
# Error Handling
Source: https://docs.roundproxies.com/residentials/error-handling
Every error our residential proxies return, what it means, and how to fix it.
When something goes wrong, the error either comes from **us** (the proxy) or from the **target site** you asked for. Telling them apart used to require guesswork. Now it doesn't:
Every error generated by the proxy carries an **`X-Proxy-Error`** response header with a stable code like `PX1002`. If that header is absent, the response came from the target site and we passed it through untouched.
The response body repeats the code on its first line, so you can read it without inspecting headers:
```http theme={null}
HTTP/1.1 502 Bad Gateway
X-Proxy-Error: PX1002
Content-Type: text/plain; charset=utf-8
PX1002: no exit node available for the requested targeting
```
**On `https://` URLs, most clients hide this.** An HTTPS request opens a tunnel with `CONNECT`, and when that fails, libraries like Python `requests`, Node `axios` and Go's `http.Client` raise a connection error instead of returning a response — so the header and body never reach your code. You get the status only: `Tunnel connection failed: 502 Bad Gateway`.
The code is still on the wire. `curl -v` shows it, and the [table below](#reading-the-code-on-https) maps each status back to its possible causes. On `http://` URLs the header is always readable.
Where you can read the code, match on it rather than on the HTTP status: statuses are shared with the target site, while the codes are ours alone and will not change.
## Errors you can fix
These mean the request needs to change. Retrying it unchanged returns the same error.
| Code | Status | Meaning | Fix |
| -------- | ------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PX1004` | `400` | Unsupported targeting option in username. | Check the spelling of your `country`, `state`, `city` or `isp` segment. Use lowercase, dash-separated values (`city-berlin`). Remove options one at a time to find the bad one — see [Basics](/residentials/basics). |
| `PX2001` | `407` | Invalid proxy credentials. | Verify your credentials in the [dashboard](https://app.roundproxies.com/dashboard/residential). The username must start with `client-CLIENT_ID`, and your client must send `Proxy-Authorization`, not `Authorization`. |
| `PX2002` | `407` | Bandwidth limit exceeded. | Your plan's data is used up and no new sessions can start. Top up or upgrade — the proxy resumes automatically. |
| `PX2005` | `503` | Bandwidth limit reached mid-request. | Same as `PX2002`, but you ran out partway through. Any response you received is incomplete. |
| `PX2003` | `403` | Destination port not allowed. | Mail (SMTP, POP3, IMAP), FTP, SSH and Telnet ports are blocked. Ports `80` and `443` always work. |
| `PX2004` | `400` | Malformed request target. | Plain HTTP needs an absolute URL in the request line; HTTPS needs `CONNECT host:port`. Check your client's proxy settings. |
A `407` now only ever means **your** credentials or **your** data balance. It is never a problem on our side, so re-sending the password will not help when the cause is `PX2002`.
## Errors worth retrying
These are conditions in the exit network. The same request will often succeed a moment later.
| Code | Status | Meaning | What to do |
| -------- | ------ | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `PX1002` | `502` | No exit node matches your targeting right now. | Narrow targeting has fewer nodes and runs dry at busy times. Retry shortly, or drop the most specific parameter — city first, then state. |
| `PX1005` | `504` | Timed out establishing the connection. | Retry. Wider targeting connects faster, because there are more nodes to choose from. |
| `PX1006` | `503` | Exit network unavailable. | A problem on our side, not with your request. Retry shortly; contact support if it lasts more than a few minutes. |
| `PX1000` | `502` | Upstream network error. | Retry with backoff. If it persists, send us the code, the time, and the target host. |
| `PX1001` | `502` | Exit network rejected the session. | Usually temporary and on our side. Retry in a moment. |
Use exponential backoff and rotate to a new `session-SESSION_ID` between attempts. Hammering the same session and the same narrow targeting tends to hit `PX1002` repeatedly.
## Errors about the destination
| Code | Status | Meaning | What to do |
| -------- | ------ | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PX1003` | `403` | The exit network does not permit this destination host, port or protocol. | Check the address and port. Contact support if you believe it should be reachable. |
| `PX1007` | `502` | The destination refused the connection. | The target is not listening on that port, or it is blocking that exit IP. Verify host and port, then retry — a different exit node may be accepted. |
| `PX1008` | `502` | Sticky session exhausted. | Change the session ID in your username to start a fresh session. Your account's data balance is unaffected. |
## Errors from the target site
If a response has **no `X-Proxy-Error` header**, it came from the site you requested and reached you exactly as they sent it. We never rewrite a target's status code, headers or body.
| Status | Meaning | Fix |
| ----------------------- | --------------------------------- | -------------------------------------------------------------------------------------- |
| `403 Forbidden` | The site is blocking the request. | Rotate to a new session for a fresh IP, and try different country or region targeting. |
| `429 Too Many Requests` | The site is rate-limiting you. | Slow down and rotate IPs more often. |
| `404`, `5xx` | The site's own error. | Handle as you would without a proxy. Retry `5xx` with backoff. |
This is why matching on the `PX` code matters: a `403` from us (`PX1003`) and a `403` from the target site mean completely different things and need completely different fixes.
## Handling errors in code
On `http://` URLs, read the header directly:
```python theme={null}
import requests
proxy = "http://client-CLIENT_ID-country-de-session-abc123:PASSWORD@residential.roundproxies.com:5000"
r = requests.get("http://example.com", proxies={"http": proxy})
code = r.headers.get("X-Proxy-Error")
if code is None:
pass # the target site answered; r is their response
elif code in ("PX1000", "PX1001", "PX1002", "PX1005", "PX1006"):
pass # transient — retry with backoff, new session
elif code in ("PX2002", "PX2005"):
pass # out of data — stop and top up
else:
pass # your request needs fixing — do not retry
```
On `https://` URLs, catch the proxy error and branch on the status in its message:
```python theme={null}
import requests
proxy = "http://client-CLIENT_ID-country-de-session-abc123:PASSWORD@residential.roundproxies.com:5000"
try:
r = requests.get("https://example.com", proxies={"https": proxy})
except requests.exceptions.ProxyError as e:
text = str(e) # "... Tunnel connection failed: 502 Bad Gateway"
if "502" in text or "503" in text or "504" in text:
pass # transient — retry with backoff, new session
elif "407" in text:
pass # your credentials, or you are out of data
else:
pass # 400 or 403 — your request needs fixing
```
To see the exact code while debugging an HTTPS failure, use `curl -v` and read the `CONNECT` response:
```bash theme={null}
curl -v -x "http://client-CLIENT_ID-country-de:PASSWORD@residential.roundproxies.com:5000" \
https://example.com
# < HTTP/1.1 502 Bad Gateway
# < X-Proxy-Error: PX1002
```
### Reading the code on HTTPS
When you only have the status, this is what it narrows down to:
| Status | Possible codes | Safe to retry? |
| ------ | ------------------------------------------------ | ----------------------------------------------- |
| `400` | `PX1004`, `PX2004` | No — fix the username or the request. |
| `403` | `PX1003`, `PX2003` | No — the destination or port is not allowed. |
| `407` | `PX2001`, `PX2002` | No — check credentials, then your data balance. |
| `502` | `PX1000`, `PX1001`, `PX1002`, `PX1007`, `PX1008` | Yes, with backoff and a new session ID. |
| `503` | `PX1006`, `PX2005` | Yes, unless you are out of data. |
| `504` | `PX1005` | Yes — and consider broader targeting. |
## Connection-level failures
Some failures happen before any HTTP response exists, so they carry no code:
| Symptom | Meaning | Fix |
| ------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `Connection refused` / `reset` reaching the proxy | You could not reach us at all. | Check outbound firewall rules and confirm you are using port `5000`. |
| Response body cut off mid-transfer | Your data ran out while streaming, or the session was closed. | Check your balance — a truncated body with no error is the signature of hitting your limit mid-download. |
## Still stuck?
Reach out at [team@roundproxies.com](mailto:team@roundproxies.com) or visit the [Help Center](https://help.roundproxies.com/en). Quote the `PX` code and the time of the request — it tells us exactly which stage failed.
# Geo-Targeting
Source: https://docs.roundproxies.com/residentials/geo-targeting
Target residential IPs by country, state, and city.
Geo-targeting lets you route requests through residential IPs in a specific country, region, or city. Add the targeting parameters to the username segment of your proxy credentials.
Only the `country` parameter is required for geo-targeting. State and city are optional refinements — the more specific the target, the smaller the available IP pool.
## Targeting Format
Add targeting parameters between your client ID and session ID:
```
client-{CLIENT_ID}-country-{COUNTRY}-state-{STATE}-city-{CITY}-session-{SESSION_ID}
```
| Parameter | Required | Description |
| --------- | -------- | --------------------------------------- |
| `country` | Yes | Country name (e.g. `Germany`, `Israel`) |
| `state` | No | State or region within the country |
| `city` | No | City within the state |
Values are lowercase, dash-separated, with no spaces or special characters (e.g. `city-newyork`, `state-northerndistrict`).
## Country Targeting
Country name of the country you would like to target.
```
country-{COUNTRY_NAME}
```
**Examples:**
* `country-Germany`
* `country-Israel`
* `country-Hungary`
## State / Region Targeting
State or region name that matches the selected country.
```
state-{STATE_NAME}
```
**Examples:**
* `state-northerndistrict` (Israel)
* `state-pestcounty` (Hungary)
* `state-citystatebremen` (Germany)
* `state-landberlin` (Germany)
## City Targeting
City name that matches the selected state.
```
city-{CITY_NAME}
```
**Examples:**
* `city-maghar` (Israel)
* `city-god` (Hungary)
* `city-bremen` (Germany)
* `city-berlin` (Germany)
## Example Request
```python Python theme={null}
import requests
proxies = {
'http': 'http://client-{CLIENT_ID}-country-Germany-state-landberlin-city-berlin-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000',
'https': 'http://client-{CLIENT_ID}-country-Germany-state-landberlin-city-berlin-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000'
}
response = requests.get('https://api.ipify.org?format=json', proxies=proxies)
print(response.json())
```
```bash cURL theme={null}
curl -x "http://client-{CLIENT_ID}-country-Germany-state-landberlin-city-berlin-session-fnzwtath:{PASSWORD}@residential.roundproxies.com:5000" \
https://api.ipify.org?format=json
```
## Tips
* Start with country only and add `state`/`city` only if your use case demands it.
* If you receive `PX1002` (no exit node available), drop the city first, then the state. See [Error Handling](/residentials/error-handling).
* Pair geo-targeting with a sticky [session](/residentials/session) to keep the same exit IP across requests.
# Session Management
Source: https://docs.roundproxies.com/residentials/session
How to maintain sessions with Residential Proxies
Sessions allow you to maintain the same IP address across multiple requests, which is essential for activities requiring consistent identity.
### Session Format
```
session-{SESSION_ID}
```
The session ID can be any alphanumeric string. Using the same session ID will route your requests through the same IP address.
**Example session IDs:**
* `session-lw515ejc`
* `session-gbyii4th`
* `session-wwmchxfs`
* `session-fnzwtath`
# Scraping Examples
Source: https://docs.roundproxies.com/scraping-examples
Drop-in scraping snippets for the most common languages and HTTP clients.
Use these copy-paste examples to send your first authenticated request through Roundproxies. Replace `USERNAME`, `PASSWORD`, and the gateway host with the values from your dashboard.
Credentials are tied to your account. Grab them from the [dashboard](https://app.roundproxies.com) before running any of the snippets below.
## Proxy Endpoint
All examples on this page point at the same gateway. Adjust the host and port to match the network you're using (residential, datacenter, or ISP).
```
http://USERNAME:PASSWORD@gate.roundproxies.com:8000
```
### Components Breakdown
| Component | Description | Example |
| ------------ | -------------------------- | ------------------------ |
| **Host** | Proxy gateway hostname | `gate.roundproxies.com` |
| **Port** | Connection port | `8000` |
| **Username** | Your account username | `USERNAME` |
| **Password** | Authentication password | `PASSWORD` |
| **Target** | The URL you want to scrape | `https://httpbin.org/ip` |
## Python
The `requests` library is the most popular choice for synchronous scraping in Python.
```python theme={null}
import requests
proxies = {
"http": "http://USERNAME:PASSWORD@gate.roundproxies.com:8000",
"https": "http://USERNAME:PASSWORD@gate.roundproxies.com:8000",
}
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)
print(r.json())
```
## Node.js
Use `axios` together with `https-proxy-agent` to route both HTTP and HTTPS traffic through the gateway.
```javascript theme={null}
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent(
"http://USERNAME:PASSWORD@gate.roundproxies.com:8000"
);
const { data } = await axios.get("https://httpbin.org/ip", {
httpAgent: agent,
httpsAgent: agent,
});
console.log(data);
```
## Go
The standard `net/http` package supports proxies out of the box via `http.ProxyURL`.
```go theme={null}
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
proxyURL, _ := url.Parse("http://USERNAME:PASSWORD@gate.roundproxies.com:8000")
client := &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
}
resp, _ := client.Get("https://httpbin.org/ip")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
```
## PHP
PHP's bundled cURL bindings make routing requests through Roundproxies a one-liner.
```php theme={null}