# ports.io documentation > Connect your application to ports.io residential proxies: authenticate, choose a location, keep a session, and understand your usage. > > Web page: https://ports.io/docs/ > Documentation index: https://ports.io/llms.txt Connect your application to residential proxies. Learn how to authenticate, choose a location, keep a session, and understand your usage. ## Make your first request Create a proxy key as a workspace owner or admin, obtain your assigned HTTP or SOCKS5 proxy URL, and send a request through `v1_rotate`. ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_rotate:$PORTS_PROXY_KEY" \ --connect-timeout 10 --max-time 30 \ https://example.com ``` Set `PORTS_PROXY_URL` to your assigned proxy URL, including its scheme, hostname, and port. Set `PORTS_PROXY_KEY` to the complete secret shown when you create a key. For SOCKS5 with curl or Python Requests, use `socks5h://` so the destination hostname reaches the proxy for the exit to resolve. Their `socks5://` mode sends a locally resolved IP address, which is refused. Use a destination hostname and the assigned SOCKS port; an HTTPS proxy's TLS-only port cannot be reused just by changing the URL scheme. HTTP proxies use the assigned `http://` or `https://` URL. See [Protocols and limits](https://ports.io/docs/reference/protocols-and-limits.md) for transport details. ## Connect your application - [Quickstart](https://ports.io/docs/guides/quickstart.md): Make your first request with an HTTP proxy or SOCKS5 with remote DNS. - [curl](https://ports.io/docs/guides/curl.md): Configure HTTP or socks5h proxies and inspect failures with curl. - [Python](https://ports.io/docs/guides/python.md): Use Requests with HTTP proxies or socks5h for remote DNS. - [JavaScript](https://ports.io/docs/guides/javascript.md): Use Undici for HTTP proxies or SOCKS5 with destination DNS at the proxy. ## Routing reference - [Authentication](https://ports.io/docs/reference/authentication.md): Authenticate HTTP or SOCKS5 with a routing username and your key as the password. - [Username format](https://ports.io/docs/reference/username-reference.md): The complete grammar, its clauses, and the validation rules. - [Geographic targeting](https://ports.io/docs/reference/targeting.md): Filter exits by country or by region. - [Sessions and rotation](https://ports.io/docs/reference/sessions.md): Rotate exits, or keep related connections on one. ## Account and operations - [Manage proxy keys](https://ports.io/docs/reference/key-lifecycle.md): Create, rename, replace, and revoke keys. - [Usage measurement](https://ports.io/docs/guides/usage.md): What the console's traffic counters include. - [Protocols and limits](https://ports.io/docs/reference/protocols-and-limits.md): HTTP and SOCKS5 support, remote DNS, size limits, and deadlines. - [Troubleshooting](https://ports.io/docs/reference/troubleshooting.md): Diagnose HTTP proxy errors and SOCKS5 handshake or tunnel failures. ## Use these docs with AI tools Every page is also published as Markdown at its address with `.md` in place of the final slash. Start an assistant from [llms.txt](https://ports.io/llms.txt), an index of every page, or give it [llms-full.txt](https://ports.io/llms-full.txt) for everything in one file. The [AI tools guide](https://ports.io/docs/guides/ai-tools.md) shows how to set up Claude Code, Codex and Cursor. Never include actual proxy secrets in prompts. --- # Make your first request > Make your first request with an HTTP proxy or SOCKS5 with remote DNS. > > Web page: https://ports.io/docs/guides/quickstart/ > Documentation index: https://ports.io/llms.txt Connect your client to an HTTP proxy or authenticated SOCKS5 endpoint with a routing username and your workspace's secret key. This guide makes one HTTPS request using a rotating route. ## Before you begin You need access to a workspace, permission to create an API key, and the proxy endpoint assigned to your account. An owner or admin can create a key. Set `PORTS_PROXY_URL` to your assigned proxy URL, including its scheme, hostname, and port. Obtain this URL before running the examples. It is separate from the console URL and from the destination website's URL. | Proxy type | URL format for curl | | --- | --- | | HTTP proxy | `http://HOST:PORT` | | HTTP proxy over TLS | `https://HOST:PORT` | | SOCKS5 with remote DNS | `socks5h://HOST:PORT` | These are formats, not real endpoints. For SOCKS5, use the assigned SOCKS port and `socks5h://` so the destination hostname reaches the proxy. curl's `socks5://` mode resolves locally and sends an IP address, which the gateway rejects. Destination URLs must use hostnames, even with remote DNS enabled. The SOCKS port can differ from the HTTPS proxy port. `socks5h://` does not add TLS to the proxy connection; changing the scheme of an HTTPS proxy URL while retaining its TLS-only port will not work. See [Protocols and limits](https://ports.io/docs/reference/protocols-and-limits.md) for transport details. ## Create a key 1. Sign in to the console and select your workspace. 2. Open **API keys** and select **Create key**. 3. Give the key a recognizable name, such as `Integration development`, and choose when it expires. 4. Copy the full `rp1_...` secret when it appears. The console shows it only once. 5. Store the secret in your application's secret store. Supply it to the examples as the `PORTS_PROXY_KEY` environment variable. The full secret is the proxy password. A key name, key ID, or masked suffix cannot authenticate a request. ## Send an HTTPS request Use `v1_rotate` as the username. The username selects the route; the password authenticates your workspace's key. ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_rotate:$PORTS_PROXY_KEY" \ --connect-timeout 10 \ --max-time 30 \ https://example.com/ ``` On Windows PowerShell, use the environment-variable syntax below and call `curl.exe` explicitly. ```powershell curl.exe --proxy "$env:PORTS_PROXY_URL" --proxy-user "v1_rotate:$env:PORTS_PROXY_KEY" --connect-timeout 10 --max-time 30 https://example.com/ ``` The command works with any of the proxy URL formats above. `--proxy-user` supplies the routing username and full key for either HTTP Basic authentication or SOCKS5 username/password authentication. The client establishes the corresponding tunnel, then performs TLS with the HTTPS destination. An `https://` HTTP proxy URL additionally protects the connection to the proxy with TLS. Keep certificate verification enabled. These timeouts are client settings for the example. Adjust them to your application. ## Recognize success A successful request returns the destination's response body. Successful HTTP or SOCKS5 tunnel setup by itself only means the tunnel opened; inspect the destination response to confirm the request succeeded. If HTTP authentication fails with `407`, or SOCKS5 reports authentication failure, check the full secret, key expiration, routing username, and workspace status. If SOCKS5 reports a connection-not-allowed reply, check that remote DNS is enabled and the destination is a hostname. See [errors and troubleshooting](https://ports.io/docs/reference/troubleshooting.md). ## Choose your next step - Use [curl](https://ports.io/docs/guides/curl.md), [Python](https://ports.io/docs/guides/python.md), or [JavaScript](https://ports.io/docs/guides/javascript.md) in your application. - Add [country and region targeting](https://ports.io/docs/reference/username-reference.md). - Keep related connections together with a [sticky or fixed session](https://ports.io/docs/reference/sessions.md). - Read [usage measurement](https://ports.io/docs/guides/usage.md) before comparing proxy traffic with application payload sizes. --- # Use curl > Configure HTTP or socks5h proxies and inspect failures with curl. > > Web page: https://ports.io/docs/guides/curl/ > Documentation index: https://ports.io/llms.txt Use curl to make a request through an HTTP or SOCKS5 proxy and inspect a connection before configuring a larger application. Set `PORTS_PROXY_URL` to your assigned proxy URL, including its scheme, hostname, and port. Supply the full `rp1_...` key as `PORTS_PROXY_KEY`. ## Configure the proxy transport | Proxy URL format | Behavior | | --- | --- | | `http://HOST:PORT` | HTTP proxy over plaintext TCP | | `https://HOST:PORT` | HTTP proxy with TLS to the proxy | | `socks5h://HOST:PORT` | SOCKS5 with the destination hostname resolved by the exit | These show formats only. Use your assigned endpoint, without embedded credentials, and keep the assigned port. A standard `socks5h://` connection uses plaintext TCP to the proxy, so it cannot be pointed directly at an HTTPS proxy's TLS-only port. For SOCKS5, use `socks5h://` rather than curl's locally resolving `socks5://` mode. The gateway requires a hostname and rejects destination IP addresses. `--socks5-hostname HOST:PORT` is curl's equivalent remote-DNS option. See the [curl options reference](https://curl.se/docs/manpage.html#--socks5-hostname). ## Request an HTTPS URL ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_rotate:$PORTS_PROXY_KEY" \ --connect-timeout 10 \ --max-time 30 \ https://example.com/ ``` `--proxy` identifies the proxy; `--proxy-user` supplies the routing username and full key for HTTP Basic or SOCKS5 username/password authentication. The final URL is the destination and must contain a hostname. curl opens an HTTP CONNECT or SOCKS5 tunnel, then negotiates TLS with the HTTPS destination. Keep certificate verification enabled. The timeouts here are example client settings. [curl options reference](https://curl.se/docs/manpage.html). The password is the complete secret shown when you created a key. Keep it out of source control, shared logs, and pasted diagnostics. Command arguments can be visible to other processes; use your environment's protected credential-loading method for unattended execution. ## Select a country Change the username while keeping the same endpoint and password. ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_rotate_countries_US:$PORTS_PROXY_KEY" \ --connect-timeout 10 \ --max-time 30 \ https://example.com/ ``` The route requires an eligible United States exit. A valid country code is a filter, not a guarantee that an exit is currently available. See [routing](https://ports.io/docs/reference/username-reference.md). ## Reuse a sticky route ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_sticky_session_checkout-42:$PORTS_PROXY_KEY" \ --connect-timeout 10 \ --max-time 30 \ https://example.com/ ``` Use the same session ID for connections that belong together. Sticky sessions permit failover when the selected exit becomes unavailable. `v1_fixed_session_checkout-42` requests a route that does not fail over. See [sessions](https://ports.io/docs/reference/sessions.md) before choosing between them. ## Inspect a failure For a local investigation, add `--verbose` to see connection stages. Redact proxy credentials and any destination credentials before sharing output. An error during proxy negotiation, authentication, or tunnel setup happens before the destination response; an HTTP error after tunnel establishment can come from the destination. SOCKS5 setup errors are not HTTP statuses or JSON error codes. See [errors and troubleshooting](https://ports.io/docs/reference/troubleshooting.md). On Windows PowerShell, use `curl.exe`, read variables as `$env:PORTS_PROXY_URL` and `$env:PORTS_PROXY_KEY`, and put the command on one line. --- # Use Python > Use Requests with HTTP proxies or socks5h for remote DNS. > > Web page: https://ports.io/docs/guides/python/ > Documentation index: https://ports.io/llms.txt Configure Python Requests with the same proxy for HTTP and HTTPS destinations. The proxy can be HTTP, HTTPS, or SOCKS5 with remote DNS. You need your assigned proxy URL supplied as `PORTS_PROXY_URL` and the full `rp1_...` key supplied as `PORTS_PROXY_KEY`. ## Install Requests ```sh python -m pip install "requests[socks]" ``` The `socks` extra installs the optional SOCKS dependencies. It also supports the HTTP proxy example below. [Requests SOCKS documentation](https://requests.readthedocs.io/en/latest/user/advanced/#socks). ## Make a request Set `PORTS_PROXY_URL` to your assigned proxy URL without embedded credentials. Use `http://` or `https://` for an HTTP proxy, or `socks5h://` with the assigned SOCKS hostname and port. Requests' `socks5://` mode resolves destinations locally and sends IP addresses, which this gateway rejects. The SOCKS port can differ from the HTTPS proxy port. `socks5h://` does not establish TLS to the proxy, so do not reuse a TLS-only proxy port by changing the scheme alone. The destination URL must contain a hostname. This example reads credentials at runtime and encodes them for use inside a proxy URL. ```python import os from urllib.parse import quote, urlsplit import requests endpoint = urlsplit(os.environ["PORTS_PROXY_URL"]) if endpoint.scheme not in {"http", "https", "socks5h"} or not endpoint.hostname: raise ValueError("PORTS_PROXY_URL must use http://, https://, or socks5h://") if endpoint.scheme == "socks5h" and endpoint.port is None: raise ValueError("Include the assigned SOCKS proxy port in PORTS_PROXY_URL") password = quote(os.environ["PORTS_PROXY_KEY"], safe="") username = "v1_rotate" proxy = f"{endpoint.scheme}://{quote(username, safe='')}:{password}@{endpoint.netloc}" response = requests.get( "https://example.com/", proxies={"http": proxy, "https": proxy}, timeout=(10, 30), ) response.raise_for_status() print(response.status_code) print(response.text) ``` The dictionary keys identify destination URL schemes, so they remain `http` and `https` when both values contain a `socks5h://` proxy URL. For SOCKS5, Requests sends the hostname for the exit to resolve; for an HTTP proxy and HTTPS destination, it establishes an HTTP CONNECT tunnel. TLS to the HTTPS destination is then negotiated through either tunnel. An `https://` HTTP proxy URL also encrypts the connection to the proxy. Passing `proxies` per request makes the intended configuration explicit. [Requests proxy documentation](https://requests.readthedocs.io/en/latest/user/advanced/#proxies). `timeout=(10, 30)` sets connect and read timeouts in seconds; it is not a total download deadline. `raise_for_status()` raises for an unsuccessful destination HTTP status. [Requests API](https://requests.readthedocs.io/en/latest/api/#requests.request). Keep TLS verification enabled and avoid logging the proxy URL. ## Target a country or reuse a route Replace the username in the example with a routing policy: ```python # Eligible United States exits. username = "v1_rotate_countries_US" # Related connections use the same sticky session. username = "v1_sticky_session_job-42_countries_US" # The session does not fail over to another exit. username = "v1_fixed_session_job-42_countries_US" ``` Rebuild the proxy URL after changing the username. See [routing](https://ports.io/docs/reference/username-reference.md) and [sessions](https://ports.io/docs/reference/sessions.md) for filter and failover behavior. ## Understand connection reuse A Requests `Session` can reuse established connections through HTTP or SOCKS5 proxies. `v1_rotate` selects an exit when a new tunnel opens, so several requests sent through one existing tunnel do not trigger a new exit selection. A rotation can also select the same eligible exit again. [Requests session documentation](https://requests.readthedocs.io/en/latest/user/advanced/#session-objects). Treat a Requests session, a proxy routing session ID, and destination cookies as separate concepts. A routing session controls exit selection; it does not manage your application's cookies. --- # Use JavaScript > Use Undici for HTTP proxies or SOCKS5 with destination DNS at the proxy. > > Web page: https://ports.io/docs/guides/javascript/ > Documentation index: https://ports.io/llms.txt Use an HTTP client with explicit proxy support for server-side JavaScript. This example uses Undici's `ProxyAgent` for HTTP proxies and `Socks5ProxyAgent` for SOCKS5. You need your assigned proxy URL supplied as `PORTS_PROXY_URL` and the full `rp1_...` key supplied as `PORTS_PROXY_KEY`. ## Install the client This example uses Undici 8.11.2, which requires Node.js 22.19.0 or later. Its SOCKS5 agent is marked experimental. Check the [Undici installation and compatibility table](https://github.com/nodejs/undici#install) when selecting a version for another runtime. ```sh npm install undici@8.11.2 ``` ## Make a request Save this example as `proxy-request.mjs`. Set `PORTS_PROXY_URL` to your assigned `http://`, `https://`, or `socks5h://` proxy URL, including its hostname and port, without embedded credentials. Supply the secret through `PORTS_PROXY_KEY`. The destination URL must contain a hostname. ```javascript import { fetch, ProxyAgent, Socks5ProxyAgent } from "undici"; const endpoint = process.env.PORTS_PROXY_URL; const password = process.env.PORTS_PROXY_KEY; if (!endpoint || !password) { throw new Error("Set PORTS_PROXY_URL and PORTS_PROXY_KEY"); } const username = "v1_rotate"; const uri = new URL(endpoint); let proxy; if (uri.protocol === "socks5h:") { if (!uri.port) { throw new Error("Include the assigned SOCKS proxy port in PORTS_PROXY_URL"); } // This agent sends hostnames to the proxy but accepts socks5: URLs. uri.protocol = "socks5:"; proxy = new Socks5ProxyAgent(uri, { username, password, connectTimeout: 10_000, }); } else if (uri.protocol === "http:" || uri.protocol === "https:") { const credentials = Buffer.from(`${username}:${password}`).toString("base64"); proxy = new ProxyAgent({ uri, token: `Basic ${credentials}`, }); } else { throw new Error("PORTS_PROXY_URL must use http://, https://, or socks5h://"); } try { const response = await fetch("https://example.com/", { dispatcher: proxy, signal: AbortSignal.timeout(30_000), }); const body = await response.text(); if (!response.ok) { throw new Error(`Destination returned HTTP ${response.status}`); } console.log(response.status); console.log(body); } finally { await proxy.close(); } ``` The agent is passed as the request's dispatcher. The HTTP branch attaches Basic credentials and uses HTTP CONNECT for the HTTPS destination. The SOCKS5 branch sends the routing username and full key in the SOCKS authentication handshake, then requests a tunnel to the destination hostname. Consume the response body and close the agent when it is no longer needed. [Undici ProxyAgent documentation](https://github.com/nodejs/undici/blob/v8.11.2/docs/docs/api/ProxyAgent.md). ## SOCKS5 and remote DNS Undici's `Socks5ProxyAgent` always sends destination hostnames to the proxy for resolution, but accepts `socks5:` or `socks:` URLs rather than `socks5h:`. The example adapts the configured `socks5h:` scheme for that agent while preserving the hostname, port, and remote-DNS behavior. It rejects plain `socks5://` in the shared application configuration so that the same value remains safe to use with curl or Requests. Keep the assigned SOCKS port: a standard SOCKS connection does not establish TLS to the proxy. SOCKS5 over TLS requires the assigned TLS endpoint and explicit `proxyTls` options; the example's SOCKS branch uses plaintext TCP to the proxy. TLS verification remains enabled for the HTTPS destination. [Undici Socks5ProxyAgent documentation](https://github.com/nodejs/undici/blob/v8.11.2/docs/docs/api/Socks5ProxyAgent.md). `AbortSignal.timeout(30_000)` requests cancellation after 30 seconds. Adjust this client setting to your application's needs. [Node.js AbortSignal documentation](https://nodejs.org/api/globals.html#static-method-abortsignaltimeoutdelay). Keep proxy authentication in the agent configuration. Do not put the proxy secret into a destination `Authorization` header or log the proxy URL or credentials; Base64 encoding in the HTTP branch is reversible. ## Select the route Change the username before constructing the agent: ```javascript const username = "v1_rotate_countries_US"; // Or: "v1_sticky_session_job-42_countries_US" // Or: "v1_fixed_session_job-42_countries_US" ``` See [routing](https://ports.io/docs/reference/username-reference.md) and [sessions](https://ports.io/docs/reference/sessions.md) for the meaning of these policies. ## Understand connection reuse An HTTP or SOCKS5 agent can reuse its connection to a destination. The proxy selects an exit when a new tunnel opens. Reusing one tunnel with `v1_rotate` does not rotate the exit for every application request. [Undici connection behavior](https://github.com/nodejs/undici/blob/v8.11.2/docs/docs/api/ProxyAgent.md). Browser JavaScript does not accept an Undici dispatcher. Keep the proxy secret in your application's server-side configuration. --- # Proxy authentication > Authenticate HTTP or SOCKS5 with a routing username and your key as the password. > > Web page: https://ports.io/docs/reference/authentication/ > Documentation index: https://ports.io/llms.txt Authenticate each new proxy connection with a routing username and the complete proxy key secret as the password. HTTP proxies carry these credentials in Basic authentication; SOCKS5 carries them in its username/password handshake. Both protocols use the same credentials and routing rules. ## Credentials at a glance | Field | Value | Purpose | | --- | --- | --- | | Proxy endpoint | Your assigned proxy URL | Connects your client to the proxy service | | Username | `v1_rotate`, or another valid routing username | Selects rotation, a session, and optional geographic filters | | Password | Your complete `rp1_...` secret | Authorizes proxy connections for its workspace | The example prefix `rp1_...` is a placeholder. Supply the complete secret, without extra whitespace or a newline. A key's display name, ID, or visible suffix cannot be used as its password. ## Make an authenticated request Configure your assigned endpoint and a secret in your environment, then let the client construct the protocol's authentication exchange: ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_rotate:$PORTS_PROXY_KEY" \ --connect-timeout 15 \ --max-time 30 \ https://example.com/ ``` `PORTS_PROXY_URL` and `PORTS_PROXY_KEY` are application variables used in this example. Their values must come from your service configuration and key creation flow. Include the assigned scheme, hostname, and port; do not infer a SOCKS port from an HTTPS proxy URL. For curl, use an assigned `http://` or `https://` proxy URL for HTTP proxying, or `socks5h://` for SOCKS5 with remote DNS. An HTTPS destination establishes the corresponding tunnel and then negotiates TLS with the destination. See [Protocols and limits](https://ports.io/docs/reference/protocols-and-limits.md) for transport details. ## HTTP wire format Clients send one `Proxy-Authorization` header on the initial proxy request: ```http CONNECT example.com:443 HTTP/1.1 Host: example.com:443 Proxy-Authorization: Basic ``` The Base64 input is the UTF-8 string `username:password`. Use the standard Basic authentication encoder in your HTTP library. Do not send the key in an origin `Authorization` header, a URL query parameter, or a custom bearer header. Basic authentication encoding does not encrypt the credentials. Use the proxy transport supplied for your environment and protect the key as a secret. ## SOCKS5 authentication and remote DNS Configure SOCKS5 username/password authentication ([RFC 1929](https://www.rfc-editor.org/rfc/rfc1929)) with the routing username and full key. Do not Base64-encode the password or send an HTTP `Proxy-Authorization` header inside the SOCKS handshake. The gateway does not accept anonymous authentication. With curl or Python Requests, set `PORTS_PROXY_URL` to the assigned SOCKS endpoint using `socks5h://`. This sends the destination hostname to the proxy for the exit to resolve. Their `socks5://` mode sends a locally resolved IP address, which is refused because destinations must be hostnames. The `h` selects remote DNS; it does not encrypt the proxy connection. The username and password are each limited to 255 UTF-8 bytes. Send the complete key. See the [curl](https://ports.io/docs/guides/curl.md), [Python](https://ports.io/docs/guides/python.md), or [JavaScript](https://ports.io/docs/guides/javascript.md) guide for client-specific configuration. ## Change routing without replacing the key The same key can authenticate different routing usernames: ```text v1_rotate v1_rotate_countries_US v1_sticky_session_checkout-42_countries_US v1_fixed_session_audit-42_regions_EU ``` The username never needs an account or workspace ID. The verified password identifies the workspace automatically. See [Username reference](https://ports.io/docs/reference/username-reference.md) for the complete grammar. ## Authentication failures HTTP authentication failures return `407` with `Proxy-Authenticate: Basic`. The error code distinguishes `invalid_credentials`, `key_expired`, `key_revoked`, and `account_disabled`. SOCKS5 authentication failures return an RFC 1929 failure status, without HTTP headers or a JSON error body. Invalid usernames, invalid keys, expired or revoked keys, and disabled workspaces use the same failure status. A client that does not offer username/password authentication receives a no-acceptable-methods reply before authentication starts. Check the whole username and password together: an unsupported username is also an authentication failure. Modified or wrong-environment secrets are rejected. If an unchanged key suddenly fails across otherwise valid requests, use the [troubleshooting guide](https://ports.io/docs/reference/troubleshooting.md) before creating replacement keys. Revocation and workspace status changes have a [propagation interval](https://ports.io/docs/reference/key-lifecycle.md#revoke-or-expire-a-key). ## Protect credentials - Store secrets in a secret manager or environment configuration. - Keep them out of source code, browser-delivered applications, request logs, screenshots, and support messages. - Use separate keys for applications that need independent revocation. - Replace a leaked or lost key using the [key lifecycle guide](https://ports.io/docs/reference/key-lifecycle.md). A proxy key grants proxy connection access. It is not a management API token. --- # Username reference > The complete grammar, its clauses, and the validation rules. > > Web page: https://ports.io/docs/reference/username-reference/ > Documentation index: https://ports.io/llms.txt The proxy username is a versioned routing instruction. It chooses how an exit is selected and optionally restricts the eligible geography. The proxy key secret belongs in the password field. Use the same username grammar for HTTP proxy Basic authentication and SOCKS5 username/password authentication. ## Grammar ```text v1_rotate[_regions_][_countries_][_exclude_] v1_sticky_session_[_regions_][_countries_][_exclude_] v1_fixed_session_[_regions_][_countries_][_exclude_] ``` Square brackets mark optional clauses. They are documentation notation and must not appear in your actual username. Replace angle-bracket placeholders with values. The version and strategy come first. Optional clauses may follow in any order, but each clause can appear only once. ## Strategies | Strategy | Required session clause | Behavior | | --- | --- | --- | | `v1_rotate` | None; a session clause is rejected | Select an eligible exit for each new connection | | `v1_sticky` | `_session_` | Reuse the session binding; allow failover when its exit is unreachable | | `v1_fixed` | `_session_` | Reuse the session binding; do not fail over an unreachable bound exit | Rotation does not guarantee a different exit or IP on every connection. Connection reuse also does not trigger another exit selection. See [Sessions and rotation](https://ports.io/docs/reference/sessions.md). ## Clauses | Clause | Format | Example | | --- | --- | --- | | `session` | ASCII letters, digits, dots, or hyphens; not empty | `_session_checkout-42` | | `regions` | Supported region codes separated by hyphens | `_regions_NA-EU` | | `countries` | ISO 3166-1 alpha-2 codes separated by commas | `_countries_US,GB` | | `country` | Alias for `countries` | `_country_US` | | `exclude` | ISO 3166-1 alpha-2 codes separated by commas | `_exclude_RU,BY` | `country` and `countries` refer to the same clause. Using both in one username is rejected. The parser accepts version, strategy, clause names, region codes, and country codes without regard to letter case. Session IDs preserve their spelling and case. Use consistent lowercase strategy names and uppercase geographic codes in application configuration. ## Supported regions | Code | Region | | --- | --- | | `NA` | North America | | `SA` | South America | | `AF` | Africa | | `AS` | Asia | | `EU` | Europe | Only these five region codes are accepted. Country-code validation does not imply that an exit is currently available in that country. See [Geographic targeting](https://ports.io/docs/reference/targeting.md). ## Examples ```text # Any eligible exit, selected for each new connection v1_rotate # US or United Kingdom v1_rotate_countries_US,GB # Europe, excluding Russia and Belarus v1_rotate_regions_EU_exclude_RU,BY # Reuse a session with US routing and permit exit failover v1_sticky_session_checkout-42_countries_US # Reuse a session in Europe without exit failover v1_fixed_session_audit-42_regions_EU ``` The comments above explain the examples; copy only the username line into your client. ## Validation rules - The complete username must be between 1 and 255 UTF-8 bytes. - The version must be `v1`; the previous unversioned grammar is rejected. - Session IDs use ASCII letters and digits; they cannot contain underscores, spaces, slashes, accented letters, or other punctuation beyond `.` and `-`. - Lists cannot contain empty or duplicate values. - Country codes must be recognized two-letter ISO country codes: use `GB`, not `UK`. - Region lists use `-`; country and exclusion lists use `,`. - Unknown clauses, including city, ASN, and duration clauses, are rejected. These invalid examples produce HTTP `407 invalid_credentials`, or a SOCKS5 username/password authentication failure. SOCKS5 does not return the HTTP JSON error code: ```text v1_rotate_session_demo v1_sticky v1_fixed_session_demo_1 v1_rotate_regions_EU,NA v1_rotate_countries_US,US v1_rotate_country_US_countries_GB v1_rotate_city_london ``` --- # Geographic targeting > Filter exits by country or by region. > > Web page: https://ports.io/docs/reference/targeting/ > Documentation index: https://ports.io/llms.txt Use region and country clauses in your proxy username to restrict the exits eligible for a new connection. Filters select from available exits; they do not reserve capacity or guarantee availability in a location. The same geographic clauses work with HTTP and SOCKS5 proxy authentication. They belong in the routing username, while the full proxy key is the password. ## Target a country Use a two-letter ISO country code: ```text v1_rotate_countries_US ``` To allow several countries, separate codes with commas: ```text v1_rotate_countries_US,GB ``` This permits an exit in either the United States or the United Kingdom. The singular spelling `country` is accepted as an alias for `countries`: ```text v1_rotate_country_US ``` Use `countries` consistently when generating usernames programmatically. ## Target a region Use `NA`, `SA`, `AF`, `AS`, or `EU`. Multiple region codes use hyphens: ```text v1_rotate_regions_NA-EU ``` This permits exits in North America or Europe. See the [region table](https://ports.io/docs/reference/username-reference.md#supported-regions) for names. Exits in Oceania, such as Australia and New Zealand, have no region code. Target them by country, with `AU` or `NZ`. ## Combine filters Selections within one list are combined with OR. Different filter clauses are combined with AND. Exclusions are applied to the resulting set. ```text v1_rotate_regions_NA_countries_US,MX_exclude_MX ``` The exit must match North America and must be in either the US or Mexico, then Mexico is removed. The resulting selection permits only matching US exits. | Username filters | Eligible geography | | --- | --- | | No geographic clauses | Any eligible exit | | `_countries_US,GB` | US or United Kingdom | | `_regions_NA-EU` | North America or Europe | | `_regions_EU_countries_DE,FR` | Europe and either Germany or France | | `_countries_US,GB_exclude_GB` | US only | | `_countries_US_exclude_US` | Empty selection | The last example is syntactically valid but cannot match an exit. Similarly, contradictory region and country requirements can produce an empty selection. ## Apply targeting to a session The same filter clauses work with sticky and fixed strategies: ```text v1_sticky_session_checkout-42_countries_US v1_fixed_session_audit-42_regions_EU_countries_DE,FR ``` Keep the strategy and geographic policy stable for an existing session ID. Create a new session ID when changing its policy. Reusing an active ID with different filters can produce a session policy conflict during connection setup. ## Handle unavailable locations When no eligible exit matches the request, HTTP proxying returns `502 no_exit_available`; SOCKS5 returns a general-failure CONNECT reply (`0x01`). A valid country code can still have no active exits. See [Troubleshooting](https://ports.io/docs/reference/troubleshooting.md) for protocol-specific errors. Review contradictory clauses first, then consider a broader selection appropriate to your application. Do not silently broaden geography when your application requires a specific location. The username grammar currently has no city, state, postal-code, ASN, or carrier selector. A region or country filter refers to the exit's location metadata, not the destination website's location. --- # Sessions and rotation > Rotate exits, or keep related connections on one. > > Web page: https://ports.io/docs/reference/sessions/ > Documentation index: https://ports.io/llms.txt Choose a routing strategy for each new proxy connection: rotate among eligible exits, reuse a sticky session with failover, or reuse a fixed session without failover. ## Choose a strategy | Goal | Username | Exit behavior | | --- | --- | --- | | Independent connections | `v1_rotate` | Select an eligible exit each time a connection is opened | | Prefer continuity and allow recovery | `v1_sticky_session_job-42` | Reuse the binding; permit rebinding if its exit is unreachable | | Fail instead of changing a bound exit | `v1_fixed_session_job-42` | Reuse the binding; do not fail over an unreachable bound exit | Geographic filters can be appended to each strategy. Use a new session ID if you change a session's strategy or filters. HTTP and SOCKS5 use the same routing usernames and workspace-scoped session bindings. Changing proxy protocol does not independently create a new binding when the workspace, session ID, and routing policy stay the same. ## Rotation happens at connection boundaries ```text v1_rotate_countries_US,GB ``` An exit is selected when a new proxy connection is dialed. Requests sent over an existing HTTP CONNECT or SOCKS5 tunnel continue using that tunnel's exit. An eligible exit may be selected again on a later connection. Rotation is not a promise of a unique IP, and it does not switch an established tunnel between exits. If your client library pools or reuses tunnels, one tunnel may carry several destination requests. Close or replace the connection when you need another selection. ## Sticky sessions ```text v1_sticky_session_checkout-42_countries_US ``` The first connection establishes a session binding. Later connections using the same workspace, session ID, strategy, and geographic policy reuse that binding while it remains active. If the bound exit cannot be reached during connection setup, sticky routing can attempt to bind another eligible exit. The alternative must satisfy the same policy. A target website refusing a connection does not itself cause the session to rotate to another exit. Failover applies when establishing a connection. An already established tunnel is not transparently moved or replayed after a failure. ## Fixed sessions ```text v1_fixed_session_audit-42_regions_EU ``` Fixed routing refuses exit failover for an active binding. If its bound exit cannot be reached, the connection fails. If the bound exit leaves the network, a still-active fixed binding cannot rebind: later connection setup with that ID fails. Start a new session ID to request another exit. HTTP and SOCKS5 report setup failures differently; see [Troubleshooting](https://ports.io/docs/reference/troubleshooting.md). Fixed describes the binding's failover policy. It is not a dedicated-IP reservation or a permanent IP guarantee. Exit network addresses can change. ## Session identity and policy Session IDs are scoped to the workspace authenticated by the key. Different keys from the same workspace can therefore use the same session ID and binding. Different workspaces have separate session namespaces. For independent workers, assign independent IDs: ```text v1_sticky_session_worker-01_countries_US v1_sticky_session_worker-02_countries_US ``` Keep the exact policy stable for each ID, including list ordering. An active binding with a different strategy or policy can fail during connection setup. To request another policy or start a separate binding, choose a new session ID: ```text # Original policy v1_sticky_session_job-42-us_countries_US # New policy, with a new ID v1_sticky_session_job-42-gb_countries_GB ``` ## Binding lifetime Session bindings last a limited time set by the service. The username has no TTL or duration parameter, and sending traffic through a session does not guarantee that its binding stays. Do not treat a session ID as an indefinite IP reservation or rely on an open tunnel to preserve a binding for later connections. Plan for a binding to end at any time. After it expires, a new connection may acquire another eligible exit even when it uses the same ID. Existing tunnel lifetime and session binding lifetime are separate concerns; see [Protocols and limits](https://ports.io/docs/reference/protocols-and-limits.md). --- # Manage proxy keys > Create, rename, replace, and revoke keys. > > Web page: https://ports.io/docs/reference/key-lifecycle/ > Documentation index: https://ports.io/llms.txt Create a named proxy key for an application, copy its secret once, and use it as the proxy password. Key replacement is a create, update, and revoke workflow. ## Create a key 1. Sign in to the console and select the workspace that should own the traffic. 2. Open **API keys** and create a named key using an owner or admin account. 3. Choose when it expires: in 30 days, 90 days (the default), 1 year, or never. 4. Copy the complete secret from the creation response and store it in your application's secret configuration. The current key management service requires owner or admin access for key listing and changes. Workspace selection must match the authenticated management session. Choose a name that identifies the application or environment. Names are trimmed, limited to 80 characters, and cannot contain control characters. ## One-time secret display The full password is returned only when the key is created. Later key listings contain metadata and a suffix, not the secret. Treat the suffix as an identifier for troubleshooting, never as a usable password. If you lose the secret or the creation response, create a replacement and revoke the inaccessible key. The existing secret cannot be recovered from the console's key metadata. ## Use and rename a key The key secret is the password in [HTTP proxy Basic authentication or SOCKS5 username/password authentication](https://ports.io/docs/reference/authentication.md). Routing strategy and targeting belong in the username and can be changed without issuing another key. Renaming changes the display name only. It does not replace the secret, alter its expiration, or rotate an exit. A revoked key cannot be renamed. Use separate keys when applications need independent access removal. ## Replace a key For routine replacement: 1. Create a new key with the desired name and expiration. 2. Store it in your application's secret configuration. 3. Validate that the application can authenticate using the new key. 4. Update all application instances and scheduled jobs that use the old secret. 5. Revoke the old key after the transition is complete. If a key has leaked, revoke it promptly and deploy a replacement. Revocation blocks new connections after its policy update reaches the proxy servers. It does not automatically close existing tunnels; see the propagation and tunnel behavior below. Replacement does not require changing the routing username. Session bindings are scoped to the workspace rather than a particular key; using another key in the same workspace does not independently create a new session binding. ## Revoke or expire a key Revocation is permanent. It preserves the key's ID, creator, timestamps, and associated usage history. Revoked keys cannot be re-enabled, and their history remains visible in the key list. Each proxy server reloads revoked keys and disabled-workspace policy every 30 seconds. These changes normally reach new connections within about 30 seconds; a failed reload can delay propagation. Revocation is not an instantaneous distributed operation. An expired key is rejected during new connection setup. Already established HTTP CONNECT and SOCKS5 tunnels do not recheck key validity and are not automatically closed by expiration, revocation, or a disabled workspace. They continue until a client or origin disconnects, a network failure occurs, or the 10-minute inactivity or 2-hour lifetime limit is reached. Close existing application connections you control when they must stop immediately. A key with no expiration still remains subject to revocation and workspace authorization policy for new connections. These rules apply to both HTTP and SOCKS5 authentication. ## Key issuance capacity The current service limits each workspace to 1,024 total issued keys, including retained expired and revoked keys. Revoking a key does not restore an issuance slot. Prefer stable application keys with deliberate replacement intervals over creating a key per request or per session. If the console says the workspace has reached its key issuance limit, contact support about more capacity. If it says key issuance is temporarily at capacity, try again later. In both cases existing keys keep working and can still be revoked. ## Management authentication Proxy secrets grant `proxy:connect`. Key-management requests use an authenticated console session, workspace authorization, and origin checks. The proxy password is not a bearer token for key-management endpoints. See [Authentication](https://ports.io/docs/reference/authentication.md) for the proxy connection credential format. --- # Understand usage measurement > What the console's traffic counters include. > > Web page: https://ports.io/docs/guides/usage/ > Documentation index: https://ports.io/llms.txt The console reports traffic by API key and shows a workspace usage chart. Use these measurements to understand traffic direction and trends; the bytes can differ from the payload sizes your application records. ## What the counters mean | Counter | Meaning | | --- | --- | | Uploaded | Bytes sent toward the destination through the upstream connection. | | Downloaded | Bytes received from the destination through the upstream connection. | | Total | Uploaded bytes plus downloaded bytes. | The counters include bytes carried by the upstream connection, such as forwarded HTTP headers. For HTTPS destinations reached through HTTP CONNECT or SOCKS5, the encrypted TLS traffic is carried on that connection. HTTP proxy setup messages and SOCKS5 negotiation, authentication, and CONNECT messages between your client and the proxy are excluded. HTTP and SOCKS5 use the same per-key usage measurements. Application bytes sent alongside a SOCKS5 handshake are counted when they pass through the established upstream tunnel; sending them early does not exclude them from usage. ```text uploaded bytes + downloaded bytes = total bytes ``` The totals count bytes, not requests. One tunnel can carry more than one HTTPS request. ## Read the console Open **Usage** in the console. Its **Usage by API key** table shows recorded totals for each key and retains entries for revoked keys. Revoking a key does not remove its prior usage history. The per-key table is shown to workspace owners and admins; every member sees the workspace chart. The workspace chart supports these ranges: | Range | Chart grouping | | --- | --- | | 24 hours | Hourly buckets | | 7 days | Daily buckets | | 30 days | Daily buckets | The chart range selects its time-series window, and its buckets are aligned to UTC. The per-key totals are recorded cumulative totals; they do not change to the chart's selected date range. The console formats byte values using binary units: `1 KiB = 1,024 bytes`, `1 MiB = 1,048,576 bytes`, and `1 GiB = 1,073,741,824 bytes`. ## Allow for reporting delay Usage arrives asynchronously. Select **Refresh** to retrieve currently available totals. During an outage, usage may appear later; an unchanged counter immediately after a request is not proof that no traffic passed through the proxy. Compare the same key and time window when investigating a discrepancy. Include the key's non-secret ID or name, approximate request times, and the client behavior. Keep the secret password out of diagnostics. ## Separate usage from pricing This page defines the current traffic measurements. It does not specify prices, free allowances, charging increments, invoice timing, or a billing accuracy guarantee. Refer to the commercial terms provided for your account when interpreting a charge. --- # Protocols and limits > HTTP and SOCKS5 support, remote DNS, size limits, and deadlines. > > Web page: https://ports.io/docs/reference/protocols-and-limits/ > Documentation index: https://ports.io/llms.txt The proxy supports HTTP forward requests, HTTP CONNECT tunnels, and authenticated SOCKS5 CONNECT tunnels over TCP. Destination hostnames are resolved by the selected exit. Connection and capacity settings depend on the environment serving your assigned endpoint. ## Supported proxy operations | Operation | Behavior | | --- | --- | | HTTP forward proxy | Send an absolute-form URL such as `http://example.com/path` | | HTTP CONNECT | Open a bidirectional TCP tunnel to a `host:port` destination | | SOCKS5 CONNECT | Open a TCP tunnel using username/password authentication and a destination hostname | | HTTPS destination | Establish an HTTP or SOCKS5 tunnel, then negotiate TLS with the destination | | SOCKS4, SOCKS5 BIND | Unsupported | | UDP, SOCKS5 UDP ASSOCIATE | Unsupported | ## Proxy transport and destination TLS Configure the client with the endpoint assigned for its proxy transport, including the port: | Proxy URL format | Client behavior | | --- | --- | | `http://HOST:PORT` | HTTP proxy connection over plaintext TCP | | `https://HOST:PORT` | HTTP proxy connection protected by TLS | | `socks5h://HOST:PORT` | SOCKS5 connection over plaintext TCP, with destination DNS delegated to the proxy | These are URL formats, not usable endpoints. Use your assigned hostname and port. The SOCKS endpoint can use a different port from the HTTPS proxy endpoint; changing only an `https://` URL's scheme does not configure the correct SOCKS transport. `socks5h` is the remote-DNS setting used by curl and Python Requests. Other libraries may provide a separate setting or an agent that always sends hostnames. SOCKS5 over TLS requires explicit client support and the assigned TLS endpoint; `socks5h://` alone does not enable it. See the [JavaScript guide](https://ports.io/docs/guides/javascript.md) for the agent configuration used there. An HTTPS destination URL protects traffic between the application and destination after the tunnel opens. It does not by itself protect the client-to-proxy authentication exchange. Keep certificate verification enabled for every TLS connection. The initial HTTP proxy request is HTTP/1.0 or HTTP/1.1. An established HTTP or SOCKS5 tunnel carries the destination protocol, including a client's TLS-negotiated HTTP version. ## HTTP forward requests ```http GET http://example.com/path HTTP/1.1 Host: example.com Proxy-Authorization: Basic ``` The gateway forwards one complete HTTP request per forward-proxy connection and closes the connection after its response. HTTP pipelining and subsequent requests on that same connection are not forwarded. Because each forward request opens its own connection, `v1_rotate` selects an exit for each one. Request bodies require valid `Content-Length` or HTTP/1.1 `Transfer-Encoding: chunked` framing. Duplicate framing headers, simultaneous content length and transfer encoding, and unsupported transfer encodings are rejected. `Expect: 100-continue` is supported. Proxy credentials are removed from the forwarded request head, and so are `Upgrade` headers. CONNECT is required when your application needs a persistent bidirectional tunnel rather than a single HTTP exchange, including WebSocket connections. ## CONNECT tunnels ```http CONNECT example.com:443 HTTP/1.1 Host: example.com:443 Proxy-Authorization: Basic ``` On successful setup, the proxy responds with `200 Connection Established`. Subsequent bytes are passed through the selected exit. Multiple destination requests inside that tunnel use the same exit. Tunnels can end because of origin or client disconnects, network failure, or transfer deadlines. Applications should handle disconnects without assuming an established request was replayed. ## SOCKS5 tunnels Use SOCKS5 username/password authentication: the username is a routing policy such as `v1_rotate`, and the password is the complete proxy key. The gateway requires this method; anonymous SOCKS5 and SOCKS4 are refused. HTTP and SOCKS5 use the same routing usernames, key verification, session bindings, and usage measurements. The CONNECT request must carry a hostname. With curl or Requests, configure `socks5h://` so the client passes that hostname to the proxy. Their `socks5://` mode resolves the destination locally and sends an IP address, which the gateway rejects. An IP-literal destination is also rejected when remote DNS is enabled. A successful SOCKS5 CONNECT reply opens a bidirectional TCP tunnel. Subsequent bytes pass through the selected exit, and requests that reuse the tunnel use the same exit. BIND and UDP ASSOCIATE are refused with command-not-supported replies. See [Troubleshooting](https://ports.io/docs/reference/troubleshooting.md#socks5-failures) for the handshake and reply codes. ## Format limits | Input | Current limit | | --- | --- | | Proxy username | 1 to 255 UTF-8 bytes | | Proxy password | 1 to 255 UTF-8 bytes | | Destination hostname | At most 253 ASCII bytes after IDN conversion; each label at most 63 bytes | | Initial HTTP request head | 64 KiB | | Headers in the initial request | At most 64 | | Key display name | 1 to 80 characters after trimming; no control characters | | Key expiration | 30 days, 90 days, 1 year, or no expiration | The full key secret is required. Truncating it to fit another integration's field will make authentication fail. ## Destinations Supply a destination hostname, not an IPv4 or IPv6 literal, in HTTP forward URLs, HTTP CONNECT authorities, and SOCKS5 CONNECT requests. This restriction concerns the destination, not the assigned proxy's own address. Exits resolve the hostname and apply policy to the resulting socket addresses before connecting. By default, loopback, private networks, link-local addresses, shared address space, multicast, reserved and documentation ranges, and certain IPv6 special-purpose ranges are blocked. Port zero is rejected. The service can apply additional destination restrictions. A hostname resolving only to disallowed addresses will fail; an application cannot bypass this policy with a username clause. ## Connection and capacity settings The gateway enforces limits on concurrent connections, connections per source IP, and new connection rate. Clients sharing a NAT can share source-IP limits. Capacity refusals can close a connection before its proxy handshake completes. HTTP CONNECT and SOCKS5 tunnels are subject to a 10-minute inactivity deadline and a 2-hour lifetime deadline. An HTTP forward request has 10 minutes to send its request body, and the whole exchange ends after 2 hours. Your assigned environment's surrounding infrastructure can impose shorter deadlines. The initial HTTP request head or the full SOCKS5 negotiation, authentication, and CONNECT request must finish within the environment's setup deadline. All SOCKS5 handshake steps share that deadline. Key validity is checked during connection setup. Revocation, expiration, or disabling a workspace blocks new connections; an already established tunnel is not automatically closed by those changes. See [key lifecycle](https://ports.io/docs/reference/key-lifecycle.md#revoke-or-expire-a-key) for propagation behavior. Confirm the effective limits for your assigned environment before sizing production workloads. This documentation does not define a plan quota or a guaranteed concurrency level. Use bounded concurrency, deliberate connection reuse, and limited retries with backoff. See [Troubleshooting](https://ports.io/docs/reference/troubleshooting.md) for failure behavior. --- # Errors and troubleshooting > Diagnose HTTP proxy errors and SOCKS5 handshake or tunnel failures. > > Web page: https://ports.io/docs/reference/troubleshooting/ > Documentation index: https://ports.io/llms.txt Identify the proxy protocol and the stage that failed. HTTP proxy setup can return an HTTP status, JSON error code, and `Proxy-Status` header. SOCKS5 setup returns handshake statuses and binary reply codes. A destination response received after successful tunnel setup belongs to the destination. ## HTTP proxy error reference | Status | Error code | Meaning | First action | | --- | --- | --- | --- | | `400` | `invalid_request` | Malformed proxy request or invalid hostname/port | Correct the request format | | `400` | `ip_target_unsupported` | The destination is an IP address | Use a destination hostname | | `501` | `method_not_supported` | The HTTP proxy request is neither CONNECT nor absolute-form forwarding | Use the HTTP client's proxy settings | | `407` | `invalid_credentials` | Proxy credentials or routing username are invalid | Check the username and complete key secret | | `407` | `key_expired` | The key has expired | Create a replacement key | | `407` | `key_revoked` | The key has been revoked | Use a valid replacement key | | `407` | `account_disabled` | The workspace is disabled | Check its status in the console and contact support | | `502` | `no_exit_available` | No eligible exit matches the requested route | Check filters and location availability | | `503` | `routing_unavailable` | Route selection could not complete | Retry a safe request later with bounded backoff | | `502` | `exit_unreachable` | The selected exit could not be reached | Check session policy; retry a safe request with backoff | | `504` | `exit_timeout` | The selected exit did not respond in time | Reduce immediate retries and check destination access | | `502` | `target_dns_failed` | The exit could not resolve the hostname to permitted addresses | Check the hostname and destination policy | | `502` | `target_unreachable` | The exit could not connect to the destination | Check the destination hostname, port, and availability | | `502` | `target_closed` | An HTTP forward destination closed without a response | Retry only if the request can safely be repeated | Admission limits can also close a connection before setup without a structured HTTP response. A connection can close before parsing or when its initial request misses the setup deadline. ## HTTP error shape Structured setup failures use this shape: ```http HTTP/1.1 502 Bad Gateway Proxy-Status: ports.io; error=destination_unavailable; details="target_unreachable" Content-Type: application/json {"error":{"code":"target_unreachable","message":"the exit could not connect to the target"}} ``` Use `error.code` for machine classification. The `Proxy-Status` header's `details` field carries the same code, which can help when an HTTP library exposes a failed CONNECT response's headers but not its body. Do not depend on `error.message` as a stable programmatic identifier. A `407` also includes `Proxy-Authenticate: Basic`. ## SOCKS5 failures SOCKS5 does not return HTTP `407` or a JSON error body during setup. First determine whether method negotiation, username/password authentication, or the CONNECT request failed. | Stage | Value | Meaning | First action | | --- | --- | --- | --- | | Method negotiation | `0xff` | No acceptable authentication method | Enable SOCKS5 username/password authentication | | Username/password authentication | `0x01` | Authentication failed | Check routing username, full key, expiration, revocation, and workspace status | After successful authentication, these CONNECT reply codes can occur: | Reply code | Meaning in this gateway | First action | | --- | --- | --- | | `0x01` | General failure, including an invalid request, unavailable routing, or an unreachable exit | Check request format and route; retry transient failures with backoff | | `0x02` | Destination IP address rejected by policy | Enable remote DNS and use a destination hostname | | `0x04` | Destination DNS or connection failure | Check hostname, port, reachability, and destination restrictions | | `0x06` | Selected exit timed out | Retry a safe request later with backoff | | `0x07` | Command not supported | Use CONNECT; BIND and UDP ASSOCIATE are unsupported | | `0x08` | Unknown address type | Use a SOCKS5 client that sends a domain-name address | SOCKS replies group several internal failure causes. Authentication failure does not distinguish an invalid key from an expired or revoked one. Record the client error and the stage instead of expecting the HTTP error catalog's JSON codes. For curl or Python Requests, use `socks5h://` to send the destination hostname. Their `socks5://` mode resolves locally and sends an IP address, which receives `0x02`. A destination URL containing an IP literal also fails with remote DNS enabled. See [Protocols and limits](https://ports.io/docs/reference/protocols-and-limits.md#destinations). ## Resolve authentication failures 1. Use a valid routing username such as `v1_rotate`; account IDs and key display names do not belong in it. 2. Send the complete proxy key secret as the password. Remove copied whitespace and newlines. 3. Configure proxy Basic authentication for HTTP, or username/password authentication for SOCKS5. Do not use destination authentication or a bearer token. 4. Check whether the key has expired or been revoked, whether its workspace is enabled, and whether it belongs to the assigned environment. If an unchanged key fails across valid usernames, investigate the workspace and service status before creating more keys. Repeatedly creating keys will not resolve a service outage. ## Check destination and session failures For `no_exit_available`, look for filters that contradict each other or remove every permitted country. A recognized country code can still have no active exit. For destination DNS or connection failures, check that the hostname and port are correct and reachable from a public network. Private and special-purpose destinations are blocked by default. A destination may also refuse connections or deny requests based on its own policy. For a session, preserve the strategy and filter policy associated with the ID. Choose a new ID when changing either. Fixed sessions do not fail over an unreachable bound exit. See [Sessions and rotation](https://ports.io/docs/reference/sessions.md). ## Handle admission failures and connection drops Reduce parallel connections and avoid a burst of immediate retries. Proxy setup can be rejected by source-IP, concurrency, or connection-rate limits, unavailable routing, or destination policy. After HTTP `200 Connection Established` or a successful SOCKS5 CONNECT reply, the tunnel can still close because of a network failure, an origin or client disconnect, or the idle/lifetime deadline. Established traffic is not replayed by the proxy. Retry only when your application can safely repeat the operation; use capped exponential backoff and jitter for transient failures. ## Reproduce with a minimal client Use your assigned endpoint, an existing valid key, a plain routing username, and a destination hostname: ```sh curl --proxy "$PORTS_PROXY_URL" \ --proxy-user "v1_rotate:$PORTS_PROXY_KEY" \ --connect-timeout 15 \ --max-time 30 \ https://example.com/ ``` For SOCKS5, set `PORTS_PROXY_URL` to the assigned `socks5h://` endpoint with its port. For HTTP proxying, use the assigned `http://` or `https://` endpoint. A standard `socks5h://` connection cannot be sent directly to a TLS-only proxy port. Keep verbose traces private: they can include proxy or destination credentials. Remove credentials before sharing any diagnostic output. ## Information to include in a support report - Timestamp and timezone. - Proxy protocol, endpoint, and client/library version. - Routing username, destination hostname and port, and concurrency level. - Failure stage: negotiation, authentication, tunnel setup, or destination response. - HTTP proxy status/error code, or SOCKS handshake status/reply code when available. - Key ID or visible suffix, without the full secret. - Whether a minimal request reproduces the problem and whether other destinations work. The customer-facing error response currently has no documented request-ID field. Record your own request correlation ID when troubleshooting application batches. --- # Use these docs with AI tools > Set up ports.io with Claude Code, Codex, Cursor or another AI assistant. > > Web page: https://ports.io/docs/guides/ai-tools/ > Documentation index: https://ports.io/llms.txt Claude Code, Codex, Cursor and other coding assistants can configure your client from these pages. Give the assistant the pages your task needs, add a few standing instructions to your project, then review what it writes. Every documentation page is also published as a static Markdown file. ## Copy or open a page as Markdown Under the title of every page: - **Copy page** copies the page's complete Markdown, including every code example, ready to paste into an assistant. - **View as Markdown** opens the same text as a plain file. - **Download** saves that file so you can attach it to your assistant. The Markdown files work without browser JavaScript. Copying uses your browser's clipboard access. ## Fetch Markdown directly Every page's Markdown sits at its address with `.md` in place of the final slash. For the page at `https://ports.io/docs/reference/authentication/`, fetch `https://ports.io/docs/reference/authentication.md`. The overview is at `https://ports.io/docs.md`. ```sh curl --fail --show-error --location \ https://ports.io/docs/reference/authentication.md \ --output ports-authentication.md ``` Each file starts with the page's title and summary, then a line linking the documentation index. Its links point at other pages' Markdown files, so an assistant can follow them without loading the website. ## Discover only the pages you need | File | Use it for | | --- | --- | | [llms.txt](https://ports.io/llms.txt) | An index of every page, with a summary and its Markdown address. Start here. | | [Guides index](https://ports.io/docs/guides/llms.txt) | Getting started and the language guides only. | | [Reference index](https://ports.io/docs/reference/llms.txt) | Routing rules, keys, limits, and errors only. | | [Guides bundle](https://ports.io/docs/guides/llms-full.txt) | Every guide in one file. | | [Reference bundle](https://ports.io/docs/reference/llms-full.txt) | The whole reference in one file. | | [llms-full.txt](https://ports.io/llms-full.txt) | All the documentation in one file, for offline indexing or a task that needs everything. | | [Page manifest](https://ports.io/docs/docs.json) | Titles, summaries, and addresses as JSON, for tools that list pages programmatically. | Start with `llms.txt`, then fetch the pages the task needs. Use a section bundle before the complete bundle when the task has a narrow scope. A tool must fetch or receive the text to use it; the files do not configure an assistant by themselves. ## Save the pages in your project Saved Markdown files give an assistant the complete text in every session, without a network request. Download the pages a client integration needs into a folder in your project: ```sh mkdir -p ports-io-docs for page in guides/quickstart reference/authentication \ reference/username-reference reference/sessions \ reference/troubleshooting guides/python; do curl --fail --show-error --location \ "https://ports.io/docs/$page.md" \ --output "ports-io-docs/${page#*/}.md" done ``` Replace `guides/python` with `guides/javascript` or `guides/curl` for another client, and add `reference/targeting` if you filter by location. The pages contain no secrets. ## Add standing instructions Coding assistants read a project instructions file at the start of each session. Add a short ports.io section so every session follows the same rules: ```markdown ## ports.io proxy - Before changing proxy code, read the ports.io pages in ports-io-docs/. The index of every page is https://ports.io/llms.txt. - Read PORTS_PROXY_URL and PORTS_PROXY_KEY from the environment. Never print, log, or commit the key. - The proxy username is a routing rule such as v1_rotate. The full key is the password. - For SOCKS5 with curl or Requests, use socks5h:// so the proxy resolves hostnames. - Keep TLS verification on. Never invent a proxy hostname or port. ``` Each assistant reads this section from its own file, described below. One `AGENTS.md` at your project root can serve Claude Code, Codex, and Cursor together. ## Claude Code Put the section in `CLAUDE.md` at your project root. Claude Code reads it at the start of every session. Claude Code v2.1.277 and later also read `AGENTS.md` when the project has no `CLAUDE.md`. If your project has both, add the line `@AGENTS.md` to `CLAUDE.md` so Claude Code reads both. A line such as `@ports-io-docs/authentication.md` in `CLAUDE.md` loads that page into every session. Import only the pages most tasks need, since each import takes up context. Claude Code can also read the online pages when your prompt includes their addresses. Its web fetch can ask for permission first, and it gives Claude an extract of the page rather than the whole file. For exact code examples, use the saved pages or ask Claude Code to download the Markdown with `curl`. [Claude Code memory documentation](https://code.claude.com/docs/en/memory). ## Codex Put the section in `AGENTS.md` at your project root. Codex reads `AGENTS.md` files from the project root down to your working directory, and your personal instructions from `~/.codex/AGENTS.md`. By default, Codex runs commands without network access and asks before a command needs the network. Its default web search answers from a cached index rather than fetching live pages. Save the pages before you start Codex, or approve the download when it asks. [Codex AGENTS.md documentation](https://learn.chatgpt.com/docs/agent-configuration/agents-md). ## Cursor Put the section in `AGENTS.md` at your project root, and Cursor applies it automatically. For more control over when the instructions apply, use a project rule in `.cursor/rules` instead. In a chat, @-mention a saved page such as `ports-io-docs/authentication.md`, or paste a page's address into your prompt so the agent reads that page. [Cursor rules documentation](https://cursor.com/docs/rules). ## Ask for the integration For a client integration, supply the quickstart, authentication reference, your language guide, and any required targeting or session pages. Then ask for the change: ```text Use the ports.io documentation to configure my Python HTTP client. Read the saved pages in ports-io-docs/ first: the quickstart, authentication, username, and Python pages. If a page you need is missing, find it from https://ports.io/llms.txt. Requirements: - Read PORTS_PROXY_URL and PORTS_PROXY_KEY from the environment. - Preserve the supplied proxy transport, hostname, and port. - For SOCKS5, use remote DNS: socks5h with curl or Requests, or the documented hostname-preserving agent configuration for JavaScript. - Use a destination hostname, not an IP address. - Use v1_rotate_countries_US as the proxy username. - Keep TLS certificate verification enabled. - Set explicit connect and read timeouts. - Do not log secrets or invent an endpoint. - Explain how connection reuse affects rotating routes. If a required detail is absent, identify it explicitly. Show a complete example and cite the documentation pages you used. ``` Supply the real key directly to your application's secret configuration, not to the prompt. Keep `PORTS_PROXY_URL` in runtime configuration. ## Review the generated configuration Check that the complete `rp1_...` key is the proxy password, the routing username follows the [username reference](https://ports.io/docs/reference/username-reference.md), and the proxy URL is separate from the destination URL. For SOCKS5, check remote DNS and username/password authentication. curl and Requests use `socks5h://`; the JavaScript guide adapts that scheme for an agent that sends hostnames by default. Keep the assigned port and distinguish plaintext SOCKS transport from TLS to the destination. The proxy rejects destination IP addresses. The assistant should preserve TLS verification, distinguish proxy setup errors from destination responses, and explain that rotation occurs when a new tunnel opens. It should not invent an available location, a session duration, a price, or a service guarantee. ## Keep context current Download the saved pages again after documentation changes, and re-fetch any page an assistant read online. Ask your assistant to cite the pages that support its behavior claims. Use per-page files for small tasks so unrelated documentation does not take up the context window.