Reseller API
Buy proxies, manage orders, and check your account - all over REST. Keys are per-reseller and rate limited at 1000 req/hour.
https://catproxies.com/api/v1/publicHow our reseller model works. You sell from the catalogue we assign to your account - not an open pool. Your /store lists exactly the packages an admin has enabled for you, each at the reseller price we set. Every order is paid from your prepaid balance. So your whole API surface is: read your store, buy a package, get credentials, manage and extend. There is nothing to provision or configure beyond that.
Product types
Every product in /store has a proxyType value. Use that exact value to filter the store (?proxyType=) and to tell which product an order is. This table maps each product name to its value.
| Product | proxyType value | Type |
|---|---|---|
| Standard Residential | v2resi | Bandwidth |
| Premium Residential | resix | Bandwidth |
| Custom ISP | Isp | Per-IP (city, carrier, 1 day to 3 months) |
| Dedicated ISP | IspP | Per-IP (no country) |
| Datacenter | DatacenterP | IPs + bandwidth pool |
| IPv6 | Ipv6p | Bandwidth or unlimited |
| Rotating Mobile | RotatingMobile | Bandwidth |
Authentication
API Key Format
API keys are prefixed with cp_ followed by 64 hexadecimal characters.
cp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2Using Your API Key
Include your API key in the Authorization header using the Bearer scheme:
curl -X GET https://catproxies.com/api/v1/public/account \
-H "Authorization: Bearer cp_your_api_key_here"Quick start
1See what you can sell (and your price)
curl -H "Authorization: Bearer cp_your_api_key_here" \
https://catproxies.com/api/v1/public/store2Buy a package (paid from your balance)
curl -X POST https://catproxies.com/api/v1/public/order \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "packageId": "PACKAGE_ID_FROM_STORE" }'3Read the credentials back any time
curl -H "Authorization: Bearer cp_your_api_key_here" \
https://catproxies.com/api/v1/public/order/ORDER_IDproxyCredentials: { username, password, hostip, port, ... }Rate Limits
1000 requests per hour per API key, reset at the top of each hour.
Mobile Targeting endpoints have a separate shared bucket: 60 requests per 10 minutes across all 4 mobile targeting sub-endpoints per API key. Cache responses where possible.
Check your current rate limit usage via the /account endpoint:
{
"rateLimits": {
"requestsPerHour": 1000,
"requestsUsed": 47,
"requestsRemaining": 953,
"resetAt": "2025-11-29T21:00:00.000Z"
}
}Errors
| Status Code | Description |
|---|---|
200 | Success - Request completed successfully |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid or missing API key |
403 | Forbidden - Not a reseller account or access denied |
404 | Not Found - Resource doesn't exist |
409 | Conflict. Read the message. On custom create: the charge stands and a human is finishing the order, do NOT retry (a retry would buy a second plan). On a Datacenter, IPv6 or Custom ISP renewal: another renewal of the same order is still running, or an earlier one is under review by our team. That call was not charged; wait (or contact us if it is under review) rather than retrying in a loop. |
429 | Too Many Requests - Rate limit exceeded (also the per-endpoint limiters: custom create 1/10s, exchange 1/30s) |
500 | Internal Server Error. Safe to retry a read, NOT automatically safe to retry a purchase or a renewal: read the message first. On POST /order/:id/extend, "Failed to extend proxy plan. Your balance has been refunded." means nothing happened (retry later), but "Your renewal payment went through, but it needs manual review..." means you were charged and our team is finishing it (do NOT retry). |
502 | Upstream error - the provider action failed and nothing was created/charged (safe to retry after a moment); on exchange, the message tells you if the value was already refunded (then do NOT retry). |
Error Response Format
HTTP 400
{
"type": "error",
"message": "Insufficient balance. Required: $2.50, Available: $1.00"
}Products
Buying is the same call for every product. What differs is the extra body a purchase needs, the host and port you connect to, and where the targeting flags go.
Hosts and per-IP lines come from GET /order/:id and GET /order/:id/proxies. All of them are plain unbranded IPs, safe to pass straight to your own customers. On Custom ISP you can also use your own hostname, with the same Auto option we use (see Custom ISP).
What can be renewed
| Product | Renewable | How |
|---|---|---|
| Custom ISP | Yes | POST /order/:id/extend with {} for the same length, or with a packageId from extendOptions for another length (for example a 1-day plan for 1 month). Same IPs. Replacements are not renewed. |
| Dedicated ISP | Yes | POST /order/:id/extend with {}. Another fixed 30 days at resellerPrice × the order IP count. |
| Standard Residential | Yes | Adds bandwidth. Pick a bandwidth pack from GET /order/:id/extendOptions and send its packageId to POST /order/:id/extend. |
| Premium Residential | Yes | Exactly like Standard Residential, with no extra body parameters. |
| Datacenter | Yes | POST /order/:id/extend with {}. Resets the data to the plan's full GB; your remaining days carry over. |
| IPv6 | Yes | POST /order/:id/extend with {}. Unlimited plans get days added, bandwidth plans get GB added (at most 5000 GB in total). |
| Rotating Mobile | Yes | With just the packageId, like buying it. |
Custom ISP - Quick Guide
What it is
Custom ISP (proxyType: Isp) is static ISP proxies where your customer picks everything: the tier (Standard, or Clean Score with IPs that have a fraud score of 0), the plan length (1 day, 7 days, 1 month, 2 months or 3 months), the city, and optionally the carrier (ASN) and UDP support. Up to 5 IP replacements can be bought with the plan. You pay pricePerIp × quantity + carrierFeePerIp × quantity (only with a carrier) + replacements × replacementPrice, from your balance, no VAT. You can buy it through the API or from the Store page in your reseller panel.
In the API the tier is standard, or premium which is sold as Clean Score: IPs checked right before delivery, with a fraud score of 0 when delivered; never check them on a score site through the proxy. The plan length is 1_day, 7_days, 1_month, 2_months or 3_months.
Buying
Complete Custom ISP workflow
1Your plans and prices, and the cities in stock. tier=premium for Clean Score, udp=1 for UDP-capable IPs only.
curl "https://catproxies.com/api/v1/public/custom-isp/catalog?tier=standard&udp=0" \
-H "Authorization: Bearer cp_your_api_key_here"plans.standard["1_month"] = { packageId, pricePerIp: 3.20, days: 30, minQty, maxQty, replacementPrice: 1.10 }
carrierFeePerIp: 0.35, countries[].cities[].location = "United States - New York City"2Optional: carriers in that city (same tier and udp as you will buy)
curl "https://catproxies.com/api/v1/public/custom-isp/carriers?tier=standard&location=United%20States%20-%20New%20York%20City" \
-H "Authorization: Bearer cp_your_api_key_here"carriers[] = { asn: 7922, name, stock }3Buy 5 IPs on that carrier, with 2 IP replacements
curl -X POST "https://catproxies.com/api/v1/public/order" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "packageId": "...", "ispData": { "quantity": 5, "location": "United States - New York City",
"asn": 7922, "udp": false, "replacements": 2 } }'Charged: 3.20 × 5 + 0.35 × 5 + 1.10 × 2 = 19.95
| Field | Notes |
|---|---|
packageId | From GET /custom-isp/catalog, plans[tier][length].packageId. One package is one tier and one length. Only tiers and lengths you have a reseller price for are listed. |
ispData.quantity | Required. Number of IPs, within the plan minQty and maxQty. |
ispData.location | Required. The city exactly as the catalog returns it, "Country - City". Or just the country (countries[].country, e.g. "United States") for IPs from any city in it: its stock is countries[].total, and it always uses any carrier (no asn). |
ispData.asn | Optional. A carrier from GET /custom-isp/carriers for that city. Adds carrierFeePerIp per IP. |
ispData.udp | Optional. true = only IPs with UDP support. Ask the catalog and carriers with udp=1 so the counts match. |
ispData.ip2locationIsp | Optional, beta. true = you only get IPs that IP2Location (a well-known IP lookup database) marks as "ISP", meaning a home or fixed internet line, not business or hosting. Checked on every IP right before delivery, at no extra cost. Not every IP has this mark, so fewer IPs are available than the stock shows: for bigger orders use a big city or a whole country. On Clean Score it comes on top of the usual fraud score 0 check on IPQS. Default false. |
ispData.replacements | Optional, 0 to 5. Each costs the plan replacementPrice. Used with POST /order/:id/replace. Not renewed. IP replacements can only be bought together with the order: they can't be added later, so choose how many you need when you buy. |
Tiers | standard = "Standard". premium = "Clean Score": IPs checked right before delivery, with a fraud score of 0 when delivered. Checking an IP on a score site through the proxy raises its score, so check it from a connection that is not using the proxy. clean_score is true on these orders. |
Stock | The catalog counts are at most a minute old. POST /order checks stock again before charging; a city or carrier that ran out is refused and nothing is charged. |
Delivery | If no IP can be delivered on the spot, POST /order answers HTTP 202 with payload.settingUp true and payload.order (PENDING): you were charged and it retries by itself after 2, 7 and 12 minutes. Do not order again; follow it with GET /order/:id. If it still gets no IP it becomes CANCELED and the price is back on your balance automatically. Ordering the exact same choice again while one is still retrying cancels and refunds the earlier one. If the provider never answers clearly, the order is held for our team instead of refunded. |
Same choice paused | If your last 3 orders for one exact choice (tier, location, asn, udp, IP2Location ISP check) all got no IP, that choice is refused for a while with HTTP 409 and payload.code CUSTOM_ISP_CHOICE_BLOCKED. Nothing is charged; payload.retryAfterMinutes says when it opens again. Pick another city or carrier meanwhile. |
Proxy format / connecting
Each line from /order/:id/proxies is one IP. All lines use the same port, 1337, for both HTTP and SOCKS5. host is a plain server IP, or your own hostname once you set one up (below), never one of our names. The order has one password; each line's login carries its IP, so always build each proxy string from its own line. ip is the address the line exits from.
Get the lines (one per IP). ?region= picks the connection server, default auto.
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/proxies?region=auto" \
-H "Authorization: Bearer cp_your_api_key_here"<host>:<port>:<login>:<password> # line format
http://<login>:<password>@<host>:1337 # HTTP / HTTPS
socks5://<login>:<password>@<host>:1337 # SOCKS5, same port| Field | Notes |
|---|---|
?region= | Connection server for the lines; connection_regions lists them. Only the route changes, not the exit IP. auto (default): with your own hostname it is your hostname itself, which answers with the server closest to YOUR customer. Without one, it is the server IP closest to where each line's IP is. |
host | A plain server IP, picked per order. Servers can change, so read the lines from the API each time instead of saving them. With your own hostname set up, host is that hostname (or <location>.<your hostname>), which always follows our server changes. |
GET /order/:id | port "1337", auth_mode "logpas" and a note pointing to /proxies and /replace. package_region holds the pick as JSON: { kind: "customisp", tier, location, asn, udp, length, replacements, carrierName }. |
Your own hostname (white label with Auto)
Put the lines on a subdomain of your own domain, e.g. isp.yourbrand.com. We serve the same records we use: isp.yourbrand.com is Auto (it answers with the server closest to whoever connects) and <location>.isp.yourbrand.com is one location (us-east, us-central, us-west, ca, uk, nl, de, fi, sg, jp, au). Dead servers are taken out for you, like on ours. Nothing in the lines or in a DNS lookup of the A records points back to us. You can also do this from the API page of your reseller panel.
1Add your hostname. The reply lists the 2 NS records to add.
curl -X POST "https://catproxies.com/api/v1/public/custom-isp/domain" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "domain": "isp.yourbrand.com" }'status "pending", records: [ { type: "NS", name: "isp.yourbrand.com", value: "kiki.bunny.net" },
{ type: "NS", name: "isp.yourbrand.com", value: "coco.bunny.net" } ]2Add those 2 NS records at your DNS provider, then check. It switches on by itself once they are seen.
curl "https://catproxies.com/api/v1/public/custom-isp/domain" \
-H "Authorization: Bearer cp_your_api_key_here"status "active", hosts: { auto: "isp.yourbrand.com", "us-east": "us-east.isp.yourbrand.com", ... }| Field | Notes |
|---|---|
domain | A subdomain of a domain you own (at least 3 parts, e.g. isp.yourbrand.com). One per account. Do not add A or CNAME records for it: the 2 NS records hand that name to us. |
status | none, pending (waiting for your NS records; lines keep using plain server IPs) or active (lines use your hostname). GET checks again on every call while pending, at most every 20 seconds. DNS changes can take up to an hour. |
DELETE /custom-isp/domain | Removes it. Your lines go back to plain server IPs right away; remove the NS records on your side too. |
Renewing
1Check the price of each length (one option per length, the plan's own first)
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/extendOptions" \
-H "Authorization: Bearer cp_your_api_key_here"2Renew for the plan's own length (empty body)
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/extend" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{}'Charged: 3.20 × 5 + 0.35 × 5 = 17.75 (replacements are not renewed)
3Or renew for another length, e.g. a 1-day plan for 1 month: the id of that option
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/extend" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "packageId": "PACKAGE_ID_FROM_EXTENDOPTIONS" }'| Field | Notes |
|---|---|
Renewal | POST /order/:id/extend with {} renews for the plan's own length. To renew for another length (1 day, 7 days, 1 month, 2 or 3 months), send the packageId of that option from GET /order/:id/extendOptions. Same IPs, at your price per IP for that length × IPs, plus carrierFeePerIp × IPs when the order has a carrier. One renewal at a time; an order under review cannot be renewed; if the result is unclear the payment is kept and our team checks it. If only some IPs could be renewed you still get 200: the order is flagged and our team completes the rest, so do not renew again. |
Good to know
Please do not check the IPs through the proxy
We check every IP before delivery. Visiting IP check or fraud score sites (IPQS and similar) through the proxy can raise the IP's fraud score, because those sites log every visit. To check an IP, look it up from another device or a connection that is not using the proxy, and ask your customers to do the same.
| Field | Notes |
|---|---|
IP locations | Locations (country and city) are strictly based on the ipinfo.io database. Other IP databases can show a different city for the same IP. |
Carrier (ASN) | A renewal keeps the same IPs. A replacement IP stays in the same city with the same UDP support, but for now it can come from a different carrier (ASN). |
Stock and delivery errors | Sometimes a city or carrier runs out, or delivery fails. POST /order checks stock before charging, so most of these are refused with nothing charged. If delivery is refused after the charge, your balance is refunded straight away and the order is cancelled: buy again in a few minutes, or pick another city or carrier. If the result is unclear, we check whether the IPs were delivered and finish or refund the order within 24 hours. Do not order again in that case. |
Swap one IP for a new one in the same city (uses one replacement)
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/replace" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "ip": "203.0.113.24" }'| Field | Notes |
|---|---|
Replace IP | POST /order/:id/replace { ip }. 200 { oldIp, newIp, left }. 202 { checking: true } = still being confirmed, do NOT retry. 400 when it is not a Custom ISP order or ip is missing. The new IP is in the same city with the same UDP support; the carrier can differ. |
Not available | No reset-password, no IP whitelist and no stats endpoint on Custom ISP. |
Reseller panel | Also sold on the Store page of your reseller panel, with the same prices and the same rules as the API. |
Dedicated ISP - Quick Guide
What it is
Dedicated ISP (proxyType: IspP) is a per-IP product: order any quantity from 1 to 100 IPs at a flat resellerPrice per IP (total = resellerPrice × quantity). It is pool-based (no country to pick), the term is a fixed 30 days, and it is username:password only. Each IP is a dedicated line served from GET /order/:id/proxies.
Buying
Complete Dedicated ISP workflow
1List Dedicated ISP packages - note resellerPrice (per IP). locations[] is EMPTY (pool-based, no country). Any quantity 1-100 costs the same per IP.
curl "https://catproxies.com/api/v1/public/store?proxyType=IspP" \
-H "Authorization: Bearer cp_your_api_key_here"2Buy 5 IPs - pass only the quantity.
curl -X POST "https://catproxies.com/api/v1/public/order" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "packageId": "...", "ispData": { "quantity": 5 } }'Charged: resellerPrice × 5. Term: a fixed 30 days.
| Field | Notes |
|---|---|
ispData.quantity | Number of IPs, 1-100. Flat per-IP price across the whole range. Defaults to 1 if omitted - always send it explicitly. |
Term | Fixed 30 days. Not selectable. |
Subnet plans | A /24 block (isSubnet: true) is NOT buyable via the API (returns 400); arrange subnets with support. |
Delivery problems | If the IPs cannot be delivered right away, the error says the order was flagged to our team. Your payment is kept and we retry automatically for up to 3 hours. If it still cannot be delivered, your balance is refunded automatically. If the result is unclear, our team delivers or refunds it within 24 hours. Never re-order: POST /order is not idempotent, so a retry is a new order and a new charge. |
Proxy format / connecting
Each line from /order/:id/proxies is one dedicated proxy with its own login/password. HTTP and SOCKS5 run on different ports: use port_http for HTTP/HTTPS and port_socks for SOCKS5 and UDP-over-SOCKS5. Always read both from the API rather than assuming they match. There is no gateway host and no username-appended targeting.
Get the proxy lines (host / port / login / password per IP). Normally ready immediately; if you get HTTP 202 { pending: true }, retry in a few seconds.
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/proxies" \
-H "Authorization: Bearer cp_your_api_key_here"http://<login>:<password>@<host>:<port_http> # HTTP / HTTPS
socks5://<login>:<password>@<host>:<port_socks> # SOCKS5 (UDP supported)| Field | Notes |
|---|---|
Credentials | Not on GET /order/:id. Fetch the host:port:login:password lines from GET /order/:id/proxies. |
Provisioning | GET /order/:id/proxies may return HTTP 202 { pending: true, proxies: [] } for a few seconds after purchase; retry. stale: true = served from cache during a brief upstream blip, lines still valid. |
Renewing
1Check the renewal cost (resellerPrice × 5 for another 30 days).
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/extendOptions" \
-H "Authorization: Bearer cp_your_api_key_here"2Renew - packageId is resolved from the order, so send an empty body.
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/extend" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{}'Charged: resellerPrice × 5 again, +30 days.
| Field | Notes |
|---|---|
Renewal | POST /order/:id/extend with {}. Cost = resellerPrice × the order IP count, for another fixed 30 days. Not idempotent - serialize renew calls per order. |
Good to know
| Field | Notes |
|---|---|
IP locations | Locations are strictly based on the ipinfo.io database. Other IP databases can show a different location for the same IP. |
Standard Residential - Quick Guide
What it is
Standard Residential (proxyType: v2resi) is a bandwidth product. Buy and extend it with just the packageId - no extra body fields. Geo and session targeting are appended to the username, so one set of credentials covers every country and session. Rotating IP per request by default. Username:password only: there is no IP whitelist and no usage stats on this product.
Proxy format / connecting
Connection ports
Use the host from GET /order/:id (proxyCredentials.hostip). Pick the port for the protocol and rotation you want.
| Protocol | Rotating port | Sticky port |
|---|---|---|
| HTTP / HTTPS | 9000 | 10000 |
| SOCKS5 | 11000 | 12000 |
Targeting
Targeting - append to the username
Keep the password as-is and append flags to the username. -type-residential is required; the rest are optional.
| Target | Flag | Value format |
|---|---|---|
| Type (required) | -type-residential | always include this |
| Country | -country-us | ISO-2 code, lowercase |
| State / region | -state-california | lowercase |
| City | -city-losangeles | lowercase, no spaces |
| ASN / carrier | -asn-7922 | ASN number only |
| Sticky session | -lifetime-30-session-ab12 | minutes (max 1440) + any id |
| UDP over SOCKS5 | -requireUdp-true | SOCKS5 only, use port 12000 |
Add -lifetime-<minutes>-session-<id> to hold the same exit IP (lifetime up to 1440 minutes = 24h); omit the sticky flags for a fresh IP on every request. For UDP traffic, connect over SOCKS5 on port 12000 and append -requireUdp-true to the username; this is optional and only needed for clients that use SOCKS5 UDP (leave it off for normal HTTP/S traffic). Discover valid countries, cities and ASNs with GET /gresi-targeting-options?orderId=... (see the Targeting endpoints).
Example
# Credentials from GET /order/:id
# username: mtpeqbcevnemewc201120 password: jonxybfeuu
# host: HOST = proxyCredentials.hostip from GET /order/:id. It is a plain
# unbranded IP on purpose, so your own customers never see where the
# plan came from. HTTP 9000 rotating, 10000 sticky.1Rotating IP in the US (new IP per request) - HTTP port 9000
curl -x HOST:9000 \
-U "mtpeqbcevnemewc201120-type-residential-country-us:jonxybfeuu" \
https://ipinfo.io2Sticky IP in Los Angeles for 30 minutes - sticky HTTP port 10000
curl -x HOST:10000 \
-U "mtpeqbcevnemewc201120-type-residential-country-us-state-california-city-losangeles-lifetime-30-session-ab12:jonxybfeuu" \
https://ipinfo.io| Feature | Notes |
|---|---|
Targeting reference | GET /gresi-targeting-options?orderId=... returns the available countries, cities and ASNs for the order. |
City / state name lists | The endpoint above returns the exact set for your order. For a ready-made list of city and US-state name tokens (same lowercase, no-separator format), download the Premium Residential targeting reference - its cities / us_states / us_state_cities lists apply here too. |
Renewing
| Feature | Notes |
|---|---|
Extending | Adds bandwidth. GET /order/:id/extendOptions returns your bandwidth packs; POST /order/:id/extend with the chosen packageId. |
Good to know
| Feature | Notes |
|---|---|
Rotate password | POST /order/:id/reset-password issues a new base password (old one stops immediately; new one activates in 1-2 minutes). The targeting flags live on the username, so only the password half of your proxy strings changes. |
Authentication | Username:password only. There is no IP whitelist and no usage stats endpoint on Standard Residential. |
Premium Residential - Quick Guide
Datacenter - Quick Guide
What it is
Datacenter plans (proxyType: DatacenterP) give you a list of dedicated IPs plus a shared bandwidth pool for a fixed duration - e.g. 100 IPs / 250 GB / 30 days. At purchase you decide how the IPs split across US, CA, DE, GB and NL. Every IP is its own proxy; they all share the same username:password. Each IP works two ways: static (that exact IP every time) or rotating (a new IP on every request) by adding a -ttl-0 flag to the username.
Buying
Complete Datacenter workflow
1List Datacenter packages - note ips (IP count), bandwidth (GB pool), days
curl "https://catproxies.com/api/v1/public/store?proxyType=DatacenterP" \
-H "Authorization: Bearer cp_your_api_key_here"2Check live IP stock per country before allocating
curl "https://catproxies.com/api/v1/public/datacenterp-countries" \
-H "Authorization: Bearer cp_your_api_key_here"3Buy - country_proxies must total EXACTLY the package IP count
curl -X POST "https://catproxies.com/api/v1/public/order" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"packageId": "...",
"datacenterPData": {
"country_proxies": { "US": 60, "DE": 20, "GB": 20 },
"high_concurrency": false,
"high_priority": false,
"whitelisted_ips": false
}
}'| Field | Notes |
|---|---|
country_proxies | Must total exactly the package ips value. Allowed countries: US, CA, DE, GB, NL. Check /datacenterp-countries for live stock first - over-allocating a country fails the purchase. |
Addons | high_concurrency (more parallel connections), high_priority (priority routing), whitelisted_ips (3 whitelist slots instead of 1). Each addon enabled adds +25% to the plan price (e.g. all three = +75%). All three are booleans and must be present in datacenterPData. |
Proxy format / connecting
1Read the IP list back (ip_list is refreshed live on every call)
curl "https://catproxies.com/api/v1/public/order/ORDER_ID" \
-H "Authorization: Bearer cp_your_api_key_here"2Optional - whitelist your server IP for credential-less access
curl -X PATCH "https://catproxies.com/api/v1/public/order/ORDER_ID/whitelist" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "ip": "203.0.113.42" }'What GET /order/:id returns for Datacenter
All IPs below are documentation examples. Real ones come from the API.
{
"payload": {
"order": {
"id": "c5c7c6b5-e488-420c-b436-e90e86031751",
"package_title": "Datacenter Proxies - 1 Month - 100 IPs - 250GB",
"status": "CONFIRMED",
"proxyCredentials": {
"username": "dcuser482913",
"password": "dcpass91827",
"total_bandwidth": 250,
"used_bandwidth": 12.4,
"bandwidth_left": 237.6,
"available_bandwidth": 237.6,
"expired_at": "2026-08-04T10:00:00.000Z",
"port_http": "1338",
"port_socks5": "1339",
"whitelist_ip": [],
"ip_list": [
{
"iso2": "US",
"name": "United States",
"count_ips": 60,
"cities": [
{ "name": "New York", "ips": ["203.0.113.24", "203.0.113.57", "..."] }
]
},
{ "iso2": "DE", "name": "Germany", "count_ips": 20, "cities": ["..."] },
{ "iso2": "GB", "name": "United Kingdom", "count_ips": 20, "cities": ["..."] }
],
"country_list": {
"countries": { "US": 60, "DE": 20, "GB": 20 },
"total": 100
},
// One rotating gateway per country this order has IPs in,
// picked for THIS order. Read it from here every time; do not save it.
"rotating_gateways": {
"US": "198.51.100.10",
"DE": "198.51.100.40",
"GB": "198.51.100.50"
},
// Every usable gateway per country. The US has two.
"rotating_gateway_sets": {
"US": ["198.51.100.10", "198.51.100.20"],
"DE": ["198.51.100.40"],
"GB": ["198.51.100.50"]
},
"rotating_bound_ip_conflicts": []
}
}
}
}Ports: 1338 HTTP and HTTPS, 1339 SOCKS5.
Using the proxies
# Every IP in ip_list is a dedicated proxy. Same credentials on all of them.
# HTTP: <ip>:1338:<username>:<password>
# SOCKS5: <ip>:1339:<username>:<password>1STATIC - that exact IP every time
curl -x 203.0.113.24:1338 -U "dcuser482913:dcpass91827" https://ipinfo.io2ROTATING - a new IP on every new connection: use rotating_gateways.<COUNTRY> from GET /order/:id as the host and append -ttl-0 to the USERNAME.
curl -x 198.51.100.10:1338 -U "dcuser482913-ttl-0:dcpass91827" https://ipinfo.io3After whitelisting your server IP, credentials are optional (static only):
curl -x 203.0.113.24:1338 https://ipinfo.io| Field | Notes |
|---|---|
Bandwidth | One shared GB pool across all IPs in the plan. Track it via bandwidth_left on GET /order/:id (refreshed live). |
ip_list | Grouped by country then city. Flatten cities[].ips to get every proxy IP. Refreshed live on each GET /order/:id. |
Authentication | username:password on any IP, or whitelist your server IP (PATCH /order/:id/whitelist) and connect without credentials. |
Rotating IPs | Use rotating_gateways.<COUNTRY> from GET /order/:id as the host and append -ttl-0 to the username for a new IP on every new connection, drawn from that order's own IPs in that country; omit the flag for a fixed IP. The gateway is picked per order, so read it from the API instead of hardcoding it. rotating_gateways only lists the countries this order has IPs in. Do not use one of your own ip_list IPs as the rotating host: with a whitelisted IP, a request through one of the order's own IPs is logged in by IP, the username is ignored and it always exits from that IP. |
Rotation granularity | Per connection, not per request. Open a fresh connection for a new IP. |
US rotating | The US has two gateways and each one only reaches about half of an order's US IPs. rotating_gateway_sets.US lists every usable US gateway for that order (normally two): point your own hostname's A-records at EVERY one of them to rotate through every US IP. |
rotating_bound_ip_conflicts | Countries where the order owns the only rotating gateway. Rotating there keeps giving the same IP while an IP is whitelisted, so remove the whitelisted IP if your customer needs rotating in that country. Static IPs are not affected. |
Worldwide rotating | One blended worldwide line is only possible for plans that include ALL five countries (US, CA, DE, GB, NL). Each gateway only accepts plans that own IPs in its country, so on a plan with fewer countries a worldwide host returns 407 whenever it lands on a country you did not buy. For such plans use one rotating_gateways line per purchased country. |
Renewing
1Renew before the end date: check the price, then renew (empty body)
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/extendOptions" \
-H "Authorization: Bearer cp_your_api_key_here"2Renew (empty body)
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/extend" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{}'| Field | Notes |
|---|---|
Renewing | Supported. GET /order/:id/extendOptions returns one option: this order's own package at your resellerPrice × the add-on multiplier (+25% per add-on bought with the plan), which is exactly what the renewal charges (no VAT). POST /order/:id/extend with {} renews the same plan. Renewing resets your data to the plan's full GB for the new term. Any data you haven't used yet doesn't carry over. Your remaining days do: the new term is added on top of your current end date. One renewal per plan at a time. See Renewing a Datacenter or IPv6 plan below. |
Renewing a Datacenter or IPv6 plan
Three calls: check the price, renew, then read the order for the new end date. Datacenter and IPv6 always renew the order's own package, so there is nothing to choose. The price check charges nothing.
1Check the price. Charges nothing. There is exactly one option: packages[0].price is what step 2 takes from your balance (no VAT), packages[0].note says what the renewal does to the data and days.
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/extendOptions" \
-H "Authorization: Bearer cp_your_api_key_here"2Renew. Empty JSON body: the order's own package is used.
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/extend" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{}'payload.extendOrderId, and payload.order with the new proxyCredentials.expired_at already in it
3Read the order again any time: proxyCredentials.expired_at is the end date, bandwidth_left the data left.
curl "https://catproxies.com/api/v1/public/order/ORDER_ID" \
-H "Authorization: Bearer cp_your_api_key_here"- Renew before the end date. An expired plan cannot be renewed (403 "Cannot extend an expired proxy"); buy a new one instead.
- Datacenter: the price is your resellerPrice × the add-on multiplier (+25% for each add-on the plan was bought with). Renewing resets your data to the plan's full GB for the new term. Any data you haven't used yet doesn't carry over. Your remaining days do: the new term is added on top of your current end date.
- If step 2 times out or you are not sure it landed, do step 3 before trying again. A renewal that went through has moved expired_at. Sending it again would renew, and charge, a second time.
- Two 500 messages mean opposite things. "Failed to extend proxy plan. Your balance has been refunded." means nothing happened: try again later. "Your renewal payment went through, but it needs manual review by our team..." means you WERE charged and our team finishes it within 24 hours or refunds it: do not retry.
- One renewal per order at a time: a call that arrives while one is still running gets 409 and is not charged. A 409 "This plan's last renewal is being checked by our team" means an earlier renewal is under review: contact us, do not renew again.
- Related: POST /order/:id/reset-password rotates the password on both products (the flags live on the username, so only the password half of your proxy strings changes), and GET /order/:id/stats shows how the plan is being used.
Usage stats
Usage stats: traffic over time, recent connections, top sites
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/stats" \
-H "Authorization: Bearer cp_your_api_key_here"| Field | Notes |
|---|---|
Usage analytics | GET /order/:id/stats: traffic and requests over time, recent connections and top sites. See Usage stats below. |
Good to know
| Field | Notes |
|---|---|
Rotate password | POST /order/:id/reset-password issues a new 12-character password shared by every IP. It takes a few minutes to switch over on every location, and until then the old one may still work on some. Only the password changes - swap it into all your proxy strings. |
HTTP 429 | Returned by the proxy when you hit the plan’s concurrent-connection limit - lower parallelism, or buy with the high_concurrency addon for a higher limit. 407 = wrong credentials / non-whitelisted IP. |
IPv6 - Quick Guide
What it is
IPv6 plans (proxyType: Ipv6p) rotate through a huge pool of IPv6 addresses - a fresh exit IP on every request by default. Two plan flavors in /store: bandwidth plans (GB pool, no speed cap) and unlimited plans (bandwidth "0" = no GB cap, speed capped at the speed value in Mbps). Purchase needs only the packageId - no extra body fields.
| Field | Notes |
|---|---|
Bandwidth plans | bandwidth > 0 in /store. Track usage via bandwidth_left / usage on GET /order/:id (refreshed live). |
Unlimited plans | bandwidth "0" + speed cap in Mbps. usage is null in /order/:id - only expired_at limits the plan. |
Proxy format / connecting
Connection gateways
IPv6 is served through country gateways - the exit country is chosen by which gateway you connect to, and the same username:password works on all of them. Locations: Worldwide, United States, Germany, United Kingdom, Netherlands. Ports: 1338 HTTP/HTTPS, 1339 SOCKS5.
The gateway addresses are returned per order by GET /order/:id - unbranded plain IPs, safe to pass straight to your own customers:
curl "https://catproxies.com/api/v1/public/order/ORDER_ID" \
-H "Authorization: Bearer cp_your_api_key_here"What GET /order/:id returns for IPv6
{
"proxyCredentials": {
"username": "...",
"password": "...",
"hostip": "<worldwide gateway>", // default gateway
"port": "1338",
"ports": { "http": "1338", "socks5": "1339" },
"endpoints": { // one gateway IP per country
"ww": "...", "us": "...", "de": "...", "gb": "...", "nl": "..."
},
"usage": { "bandwidth_left": 87.4, ... } // null on unlimited plans
}
}The target site must support IPv6
Exits are IPv6-only, so the destination needs an AAAA (IPv6) DNS record. Major platforms (Google, YouTube, Facebook, Instagram, TikTok) support it; many smaller sites do not and will be unreachable. Check your target domain first at ready.chair6.net, then confirm the proxy works end-to-end by requesting https://api6.ipify.org through it. An unreachable IPv6-less target typically surfaces as a 503 from the proxy.
Targeting
Sessions - append to the username
Default is rotating: a new IPv6 address on every request, nothing to configure. For a sticky session (keep the same exit IP), append -session-<id>-ttl-<seconds> to the username (password unchanged). The session id must be a number between 0 and 999999; ttl is the hold time in seconds, up to 86400 (24h) - e.g. ttl-1800 = 30 min, ttl-3600 = 1 hour. Use different session ids to hold several sticky IPs in parallel.
# Credentials + gateway IPs from GET /order/:id (same login on all gateways)
# username: ipv6user291 password: v6pass817
# endpoints.us -> US_GATEWAY, endpoints.de -> DE_GATEWAY, ...
# Those gateways are plain unbranded IPs on purpose, so your own customers
# never see where the plan came from. HTTP 1338, SOCKS5 1339.1Rotating - fresh IPv6 address on every request (US gateway)
curl -x US_GATEWAY:1338 -U "ipv6user291:v6pass817" https://api6.ipify.org2Sticky - hold the same IPv6 exit for 60 minutes (ttl is in SECONDS: 60 min = 3600)
curl -x DE_GATEWAY:1338 \
-U "ipv6user291-session-483920-ttl-3600:v6pass817" \
https://api6.ipify.org3SOCKS5
curl --socks5 US_GATEWAY:1339 -U "ipv6user291:v6pass817" https://api6.ipify.org| Field | Notes |
|---|---|
Sticky session | -session-<id>-ttl-<seconds> appended to the username. id numeric 0-999999; ttl is the hold time in SECONDS, max 86400 (24h) - e.g. 1800 = 30 min, 3600 = 1h. Omit both for rotating. |
Renewing
| Field | Notes |
|---|---|
Renewing | Supported. GET /order/:id/extendOptions returns one option: this order's own package at your resellerPrice (no VAT). POST /order/:id/extend with {} renews the same plan. Unlimited plans get the package's days added on top of the current end date (always the plan's own length, for example 30 days on a 30-day plan). Bandwidth plans get its GB added on top of the data left, and the end date moves forward by the plan's own term. A bandwidth plan can hold at most 5000 GB in total: a renewal that would pass that is refused before anything is charged, and extendOptions returns no option. One renewal per plan at a time. See Renewing a Datacenter or IPv6 plan below. |
Renewing a Datacenter or IPv6 plan
Three calls: check the price, renew, then read the order for the new end date. Datacenter and IPv6 always renew the order's own package, so there is nothing to choose. The price check charges nothing.
1Check the price. Charges nothing. There is exactly one option: packages[0].price is what step 2 takes from your balance (no VAT), packages[0].note says what the renewal does to the data and days.
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/extendOptions" \
-H "Authorization: Bearer cp_your_api_key_here"2Renew. Empty JSON body: the order's own package is used.
curl -X POST "https://catproxies.com/api/v1/public/order/ORDER_ID/extend" \
-H "Authorization: Bearer cp_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{}'payload.extendOrderId, and payload.order with the new proxyCredentials.expired_at already in it
3Read the order again any time: proxyCredentials.expired_at is the end date, bandwidth_left the data left.
curl "https://catproxies.com/api/v1/public/order/ORDER_ID" \
-H "Authorization: Bearer cp_your_api_key_here"- Renew before the end date. An expired plan cannot be renewed (403 "Cannot extend an expired proxy"); buy a new one instead.
- IPv6 unlimited plan: the package's days are added on top of the current end date. IPv6 bandwidth plan: the package's GB are added on top of the data left, and the end date moves forward by the plan's own term.
- If step 2 times out or you are not sure it landed, do step 3 before trying again. A renewal that went through has moved expired_at. Sending it again would renew, and charge, a second time.
- Two 500 messages mean opposite things. "Failed to extend proxy plan. Your balance has been refunded." means nothing happened: try again later. "Your renewal payment went through, but it needs manual review by our team..." means you WERE charged and our team finishes it within 24 hours or refunds it: do not retry.
- One renewal per order at a time: a call that arrives while one is still running gets 409 and is not charged. A 409 "This plan's last renewal is being checked by our team" means an earlier renewal is under review: contact us, do not renew again.
- Related: POST /order/:id/reset-password rotates the password on both products (the flags live on the username, so only the password half of your proxy strings changes), and GET /order/:id/stats shows how the plan is being used.
Usage stats
| Field | Notes |
|---|---|
Usage analytics | GET /order/:id/stats: traffic and requests over time, recent connections and top sites. See Usage stats below. |
Good to know
| Field | Notes |
|---|---|
Authentication | username:password only. IP whitelisting is currently unavailable for IPv6 plans. |
Rotate password | POST /order/:id/reset-password issues a new 12-character password (old one stops immediately; new one activates in 1-2 minutes). Targeting flags live on the username, so only swap the new password into your proxy strings. |
Proxy response codes
| Code | Meaning |
|---|---|
407 | Wrong or missing proxy credentials. |
429 | Concurrent-connection / thread limit reached - lower parallelism or retry with backoff. |
503 | Could not reach the target - DNS failed or the site has no IPv6 (AAAA) support. |
504 | The target site did not respond in time. |
Rotating Mobile - Quick Guide
What it is
Rotating Mobile (proxyType: RotatingMobile) is a bandwidth product on real mobile carriers. Buy and extend it with just the packageId. Location and session targeting are appended to the username. Rotating IP per request by default.
Proxy format / connecting
Use the host and port from GET /order/:id (proxyCredentials.hostip / port, HTTP port 5000). The same credentials work for every location; you choose the location by the username flags below.
Targeting
| Target | Flag | Value format |
|---|---|---|
| Country | -country-US | ISO-2 code |
| Region / state | -region-california | region code from /regions |
| City | -city-los+angeles | city code from /cities. Spaces are a PLUS sign. |
| Carrier / ISP | -isp-at&t+wireless | isp code from /isps |
| Sticky session | -sid-ab12-ttl-30m | any id + ttl (see below): one of 1m 5m 10m 30m 60m 120m 180m 240m |
For a sticky IP add -sid-<id>-ttl-<duration>, where duration is one of 1m 5m 10m 30m 60m 120m 180m 240m (hold up to 4h). Omit the sticky flags for a fresh IP each request. All of region, city, isp and the sticky flags are optional.
Value format: read this before targeting
- Use the codes exactly as returned by the targeting endpoints. Spaces are written as
+, never as-, e.g.los+angeles,new+york,at&t+wireless. Regions are full names (california), not 2-letter codes. - An unknown or malformed value fails with 502, and it does not silently fall back to untargeted rotation. If you get a 502 on a targeted request, check the code first.
- Carrier availability varies by city, so a valid city + carrier pair can still return 502 if that carrier has no live IPs there right now. For reliable carrier targeting, pin the carrier at country level and omit the city flag. City targeting is metro-approximate, not pinpoint.
- Untargeted rotation is not evenly weighted across carriers. If you need a specific carrier mix, request each carrier explicitly rather than relying on the default rotation.
Discovering locations
The valid country / region / city / ISP codes come from the Mobile Targeting endpoints (/mobile-targeting-options/*). Those endpoints share a limit of 60 requests per 10 minutes - cache them (the lists rarely change), or download the full offline snapshot from the Targeting section for bulk setup. For a static starting point you can also reuse the city and US-state name lists in the Premium Residential targeting reference - the same place names apply, though the exact set valid for mobile comes from the endpoints above.
Example
# Credentials from GET /order/:id
# username: mobileuser71 password: mob9182pass
# host: HOST = proxyCredentials.hostip from GET /order/:id, a plain unbranded
# IP on purpose so your own customers never see where the plan came
# from. port: 50001Rotating mobile IP in the US (new IP per request)
curl -x HOST:5000 \
-U "mobileuser71-country-US:mob9182pass" \
https://ipinfo.io2Rotating IP on AT&T anywhere in the US
curl -x HOST:5000 \
-U "mobileuser71-country-US-isp-at&t+wireless:mob9182pass" \
https://ipinfo.io3Sticky IP on AT&T in California for 30 minutes
curl -x HOST:5000 \
-U "mobileuser71-country-US-region-california-isp-at&t+wireless-sid-ab12-ttl-30m:mob9182pass" \
https://ipinfo.ioRenewing
Extend it with just the packageId, the same way you buy it.
Good to know
Resetting the login
POST /order/:id/reset-password gives the plan a whole new login and moves its remaining data onto it, so the username and the password both change. The response carries both (username and password); rebuild your proxy strings from them and re-append your targeting flags to the new username. The old login stops working straight away, and the plan's used and total GB carry over. Allowed once per hour per plan, not within 5 minutes of a top-up, and not on a plan with no data left.
Usage stats
Datacenter and IPv6 orders come with usage analytics: traffic and requests over time, a log of recent connections, and the sites used most. It is one read-only endpoint, GET /order/:id/stats, and the view parameter picks which of the three you get. It never changes the plan, so you can pass the figures straight on to your own customers.
1Traffic over the last 24 hours, one row per hour (the defaults)
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/stats" \
-H "Authorization: Bearer cp_your_api_key_here"2The last week, one row per day
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/stats?timeframe=1week&interval=1day" \
-H "Authorization: Bearer cp_your_api_key_here"3Recent connections, 100 per page
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/stats?view=activity&page=1" \
-H "Authorization: Bearer cp_your_api_key_here"4The sites used most this month
curl "https://catproxies.com/api/v1/public/order/ORDER_ID/stats?view=top-domains&timeframe=1month" \
-H "Authorization: Bearer cp_your_api_key_here"- timeframe: 1hour, 6hours, 1day (default), 1week, 1month or 3months. interval, for the overview only: 5min, 30min, 1hour (default), 6hour, 1day, 1week or 1month. An unknown value quietly falls back to the default, so check timeframe and interval in the reply.
- available: false means the stats source could not be reached just now and the lists are empty. Retry later; it does not mean zero traffic.
- The figures lag a little behind real time. For what is left on the plan right now, read proxyCredentials.bandwidth_left on GET /order/:id instead.
- Units: the overview is in GB, activity and top-domains traffic is in bytes, and success_rate is a percentage. Timestamps are "YYYY-MM-DD HH:MM:SS" strings.
- GET /order/:id/unlimited-metrics is the older name of the same endpoint and returns exactly the same thing.
API reference
Rotating Mobile - targeting endpoints
Need all countries, regions, cities, and ISPs at once? Download the full offline snapshot instead of hitting these endpoints repeatedly.
White Labeling
Every reseller order already hands you a plain IP as the host, never one of our hostnames, so nothing in the credentials you pass on points back to us. This section is for when you want to go further and give your customers a hostname on your own domain.
Our gateways
| Product | Gateway hostname | Ports |
|---|---|---|
| Standard Residential | resi-us / resi-fr / resi-sg .catproxies.com | 9000 HTTP rotating, 10000 HTTP sticky, 11000 / 12000 SOCKS5 |
| Premium Residential | presix / presix-eu / presix-asia .catproxies.com (HTTP), presix-socks / presix-eu-socks / presix-asia-socks .catproxies.com (SOCKS5) | 6011 / 6012 / 6013 HTTP, 6014 / 6015 / 6016 SOCKS5 |
| Premium Residential ISP pools | usax / usax-tk / ukx / dex / dex-dtag / aux .catproxies.com, or the isp_pools IPs on GET /order/:id | 6000 / 6001 / 6003 / 6006 / 6007 / 6002, HTTP only |
| Rotating Mobile | mobile-us / mobile-eu / mobile-asia .catproxies.com | 5000 |
| IPv6 | ipv6-ww / ipv6-us / ipv6-de / ipv6-gb / ipv6-nl .catproxies.com | 1338 HTTP, 1339 SOCKS5 |
| Datacenter | No hostname. Point your record at the rotating_gateway_sets IPs for the country on GET /order/:id (for the US, all of them, so it reaches every US IP). | 1338 HTTP, 1339 SOCKS5 |
| Dedicated ISP | No gateway. You get individual IP:port lines, and they are yours for the life of the plan. | As returned |
| Custom ISP | A plain server IP per order, or your own hostname with Auto included: set it up with POST /custom-isp/domain (see the Custom ISP guide). Use that instead of a CNAME or A records. | 1337, HTTP and SOCKS5 |
Two ways to point your domain at us
CNAME: never breaks
proxy.yourdomain.com CNAME resi-us.catproxies.comWhen we move a gateway your hostname follows on its own and you do nothing. The catch: a DNS lookup on your record shows our hostname, so anyone curious can see who is behind it.
A records: nothing links back
1Read the current IPs
dig +short resi-us.catproxies.com2Add one A record per IP (in your DNS provider)
proxy.yourdomain.com A 192.0.2.10
proxy.yourdomain.com A 192.0.2.11A lookup shows only IP addresses, so there is nothing to trace. The catch is that it goes stale: when we rotate a gateway your record points at a dead address and your customers break until you change it yourself.
If you go the A record route, read this. Add every IP the hostname resolves to, not just the first one. Most of our gateways are several nodes behind one name, and pinning a single IP throws away the failover. And gateway IPs do change: we announce every change in our update channel before it happens (Discord and Telegram), so follow one and update your records when we do. If uptime matters to you more than being untraceable, use the CNAME.
Ready to Get Started?
Create your first API key and start integrating CatProxies into your application today.
