ProxioDocs
API Reference

Proxy List

Generate ready-to-use Proxio proxy lines with GET /services/{id}/proxy-list. Targeting, including ASN, is embedded in the username, output as txt, json, or csv, with the full username grammar, every query parameter (count, sesstime, retry, retry_rotate, session_id, asn), sticky vs rotating, and practical recipes.

GET /services/{id}/proxy-list is the fastest path from a residential service to working proxies. It returns ready-to-paste connection lines with country, state, city, and session targeting already embedded in the username, so there's nothing to assemble by hand. Ask for txt, json, or csv.

Scope: read

The username grammar

Targeting is expressed as dash-separated segments appended to your base username. Every segment is optional and they're applied in this order:

{base}[-region-{cc}][-st-{state}][-city-{city}][-asn-{n}][-sessid-{id}][-sesstime-{min}][-retry-{N}][-retryrotate-1]
SegmentValueNotes
-region-{cc}ISO 3166-1 alpha-2, lowercaseCountry, e.g. us.
-st-{state}ISO 3166-2 code, lowercaseState/region; requires a country. Optional.
-city-{city}dash-free slug, lowercaseCity; requires a country. A state is not required.
-asn-{n}1 to 4294967295Target a specific network. See ASN targeting below, it behaves differently from the geo segments.
-sessid-{id}your session id, or an auto-generated onePins one IP; present only for sticky lines.
-sesstime-{min}integer minutesSession window; rejected outside 1 to 90, never clamped.
-retry-{N}integerExtra connection retries; rejected outside 0 to 20, never clamped. See the note under retry and retry_rotate.
-retryrotate-1flagTake a fresh IP on each retry.

City values are slugged to [a-z0-9] with dashes removed, because the gateway splits the username on -. So "New York" becomes newyork, not new-york, and this endpoint's own city parameter does that stripping for you. state looks similar but works differently: it's the exact ISO 3166-2 code GET /locations returns for that state (ca, not california), not a slug of its name, send the code as-is rather than a display name. See Geo-Targeting for the full rule.

Geo hierarchy: country is the only prerequisite. State and city each require a country, but they do not require each other, so country + city with no state is a valid combination. Adding a state alongside a city narrows the match further and is useful when a city name is ambiguous across states.

Query parameters

ParameterValuesDefaultNotes
formattxt | json | csvtxttxt and csv return text/*; json returns the envelope.
protocolhttp | socks5httpSets the protocol field and scheme hints; the port is the same either way.
count1 to 100010Number of lines to generate.
countryISO2, comma-separated-Repeatable; round-robins across the values.
statecode, comma-separated-Requires country. Optional.
cityslug, comma-separated-Requires country. A state is optional; add one to disambiguate a city name.
asnASN, comma-separated-Repeatable, round-robins like country. See ASN targeting.
sessionsticky | rotatingrotatingsticky gives each line a unique sessid.
session_id1 to 32 letters/digitsauto-generatedRequires session=sticky and count=1. See retry and retry_rotate for why it's paired with count.
sesstime1 to 9010Only used when session=sticky.
retry0 to 200Extra connection retries. See retry and retry_rotate.
retry_rotatetrue | falsefalseRequires session=sticky and retry of at least 1.
credential_idcredential idprimaryWhich credential's username and password to embed.

Passing state or city without a country is a VALIDATION_ERROR. Passing a city without a state is fine.

count and sesstime reject out-of-range values, they don't clamp

Every bounded numeric parameter on this endpoint, count, sesstime, retry, and asn, is validated strictly: a value outside its range, or one that isn't a whole number at all (sesstime=abc, count=1.5), fails with VALIDATION_ERROR naming the parameter. None of them are silently rounded, clamped, or defaulted to a fallback. If you're migrating from a client that used to send out-of-range values expecting them to be adjusted for you, it will now see a 400 instead.

Sticky vs rotating

This choice decides whether each line holds an IP or draws a fresh one per request:

  • rotating (default): no sessid segment. Every request through the line gets a new residential IP. Best for high-volume, independent requests where IP diversity matters.
  • sticky: each line gets its own freshly generated sessid plus -sesstime-{min}, so a line keeps the same IP for the session window. The ids are unique within a response; treat them as opaque strings rather than assuming a fixed length or format. Best for logins, carts, and any multi-step flow. Generate count sticky lines to get count independent pinned IPs.

See Session Types for the underlying rotation model.

Your own session_id

By default, a sticky line gets an auto-generated sessid. Pass your own with session_id instead, useful when you want to derive the id from your own job or user identifier rather than tracking whatever this endpoint handed back.

session_id must be 1 to 32 letters or digits, no dashes, underscores, or any other punctuation, the username grammar splits on -, so anything else would corrupt every segment after it. It also requires session=sticky (a rotating line has no session to pin) and count=1: a fixed id names one session, so asking for more than one line with it is a conflict, not a request for the same id repeated. Omit session_id and ask for count sticky lines to get count independently generated ids instead. Violating either requirement fails with VALIDATION_ERROR.

retry and retry_rotate

retry adds -retry-{N} to the username, extra connection-level retry attempts on top of the initial dial. retry_rotate adds -retryrotate-1 alongside it, so a sticky session moves to a fresh IP on each retry instead of retrying the same one; it requires session=sticky and a retry of at least 1, since it has no effect on a rotating line or with no retries requested.

A value above 5 is accepted here, but not honored at connection time

This endpoint validates retry against the username grammar's own ceiling, 0 to 20, and embeds whatever whole number you send. The proxy pool's own dial path enforces a lower ceiling of its own once you actually connect, so a line generated with, say, retry=12 is valid and usable, but only the first 5 retries happen; the rest of the number you asked for is not an error, it's just not honored. Stay at 5 or under if you want the number in the username to match the number of retries you actually get.

ASN targeting

asn targets a specific network by its autonomous system number, the same round-robin behavior as country: pass several, comma-separated or repeated, and lines cycle across them. Accepts a bare number (7018) or the conventional AS-prefixed spelling (AS7018, case-insensitive), both mean the same thing. Out-of-range or non-numeric values fail with VALIDATION_ERROR.

This endpoint returning 200 does not mean the ASN has an IP available

GET /services/{id}/proxy-list only mints credentials, it embeds -asn-{n} in a username and hands it back; it never contacts the proxy pool to check that the network actually has an IP to offer. A 200 here just means the line is well-formed. If no IP is available in the ASN you asked for, the failure happens later, at connection time, when you actually use the credential, and there's no fallback to a different ASN: the connection fails outright rather than silently landing you on a network you didn't ask for. Handle a dial failure on an ASN-targeted line as "try a different ASN or drop the constraint", not as a bug in the line you were given.

Output formats

txt (default)

text/plain, one username:password@host:port line per proxy, paste-ready:

abc123xyz-region-us-city-newyork-sessid-k3n8f2p9q1ab1-sesstime-10:[email protected]:16666
abc123xyz-region-us-city-newyork-sessid-m7b2c4d6e8fg2-sesstime-10:[email protected]:16666

Every line in one response carries the same targeting, only the sessid differs.

json

The standard envelope, with structured fields per proxy:

{
  "data": {
    "endpoint": { "host": "geo.proxio.cc", "port": 16666 },
    "protocol": "http",
    "count": 2,
    "proxies": [
      {
        "host": "geo.proxio.cc",
        "port": 16666,
        "username": "abc123xyz-region-us-sessid-m7b2c4d6e8fg2-sesstime-10",
        "password": "secretpass",
        "line": "abc123xyz-region-us-sessid-m7b2c4d6e8fg2-sesstime-10:[email protected]:16666"
      }
    ]
  },
  "meta": { "request_id": "req_8Ke2jP4mQ" }
}

csv

text/csv with a header row: host,port,username,password,protocol.

Recipes

1000 sticky US sessions for 30 minutes

A thousand independent IPs, each pinned for half an hour:

curl "https://dashboard.proxio.net/api/v1/services/clpkg_2a9x/proxy-list?count=1000&country=us&session=sticky&sesstime=30&format=txt" \
  -H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
import requests

BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
SERVICE_ID = "clpkg_2a9x"

resp = requests.get(
    f"{BASE}/services/{SERVICE_ID}/proxy-list",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"count": 1000, "country": "us", "session": "sticky", "sesstime": 30},
    timeout=30,
)
resp.raise_for_status()
lines = resp.text.splitlines()
print(f"Got {len(lines)} sticky sessions")
const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const SERVICE_ID = "clpkg_2a9x"

const query = new URLSearchParams({
  count: "1000",
  country: "us",
  session: "sticky",
  sesstime: "30",
})
const res = await fetch(
  `${BASE}/services/${SERVICE_ID}/proxy-list?${query}`,
  { headers: { Authorization: `Bearer ${API_KEY}` } },
)
const lines = (await res.text()).trim().split("\n")
console.log(`Got ${lines.length} sticky sessions`)

Per-country round-robin

Pass several countries and the generator distributes lines across them in turn:

curl "https://dashboard.proxio.net/api/v1/services/clpkg_2a9x/proxy-list?count=30&country=us,gb,de&format=json" \
  -H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
import requests

BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"

resp = requests.get(
    f"{BASE}/services/clpkg_2a9x/proxy-list",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"count": 30, "country": "us,gb,de", "format": "json"},
    timeout=15,
)
resp.raise_for_status()
for proxy in resp.json()["data"]["proxies"]:
    print(proxy["username"])
const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"

const query = new URLSearchParams({
  count: "30",
  country: "us,gb,de",
  format: "json",
})
const res = await fetch(
  `${BASE}/services/clpkg_2a9x/proxy-list?${query}`,
  { headers: { Authorization: `Bearer ${API_KEY}` } },
)
const { data } = await res.json()
for (const proxy of data.proxies) console.log(proxy.username)

City-level targeting

A city needs a country. Adding a state is optional:

# Country + city is enough:
curl "https://dashboard.proxio.net/api/v1/services/clpkg_2a9x/proxy-list?count=20&country=us&city=newyork&session=sticky&format=txt" \
  -H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"

# Add a state when the city name is ambiguous:
curl "https://dashboard.proxio.net/api/v1/services/clpkg_2a9x/proxy-list?count=20&country=us&state=ny&city=newyork&session=sticky&format=txt" \
  -H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"

Use GET /locations to discover valid country, state, and city codes.

Static IP services

For ISP and datacenter services, the IPs are fixed, so targeting doesn't apply. The endpoint returns your static proxies formatted into the requested format, with count capped to the number of proxies in the service. Passing targeting parameters (country, state, city, session) explicitly on a static service returns UNSUPPORTED_OPERATION; omit them to just format the fixed list.

On this page