# /pool - Proxies.sx Pool Gateway Access > **Rotation cookbook** (copy-paste IP rotation in curl/python/node + the footguns that trip LLMs): https://agents.proxies.sx/pool/rotation-cookbook.md > One credential reaches every country in the network through `gw.proxies.sx:7000` (HTTP) / `:7001` (SOCKS5) - the flagship peer fleet (residential + mobile IPs connected in 150 countries (~127 with live stock), scaling toward millions of devices) plus guaranteed-quality carrier modems in 6 countries. **The standard path - the main, most-used way in: create an account, mint an API key (`psx_*`), deposit GB, set a proxy password, connect.** Country, session and rotation are declared per-request in the proxy username; your deposited GB is the meter. Wallet-only agent with no account? There is an optional x402 alternative - pay USDC on-chain and get a ready credential - see [Optional: Pay with USDC (x402, no account)](#optional-pay-with-usdc-x402-no-account). > **Two products - know which one you are buying.** This file is the POOL GATEWAY: one credential on gw.proxies.sx:7000/:7001, every country in the tier - country, session and rotation are declared per-request in the proxy username. The other product is the DEDICATED PORT: one real port on one modem, its own host:port, one country fixed at purchase - the modem is exclusively yours and rotates only when YOU hit the rotate URL (carrier NAT can still re-issue the exit IP). Buy the dedicated port with your API key (`POST /v1/ports`) or wallet-only (`/v1/x402/proxy`). Pick the dedicated port for cookie-bound/login/2FA work in one country or on-demand true carrier-IP resets - its skill file is [/marketplace/skill.md](https://agents.proxies.sx/marketplace/skill.md); pick this pool credential for multi-country work, high fan-out and zero babysitting. Same $4.00/GB - the difference is topology, not price: this pool credential spans the whole network (the flagship peer fleet (~127 countries with live stock) plus the 6-country carrier modems), while a dedicated port is one carrier modem in one of those 6 countries. Full comparison: [Pool Access vs Dedicated Port](#pool-access-vs-dedicated-port---which-to-buy). **Economics:** $4.00/GB, volume-discounted to $2.40/GB at 250 GB+ per purchase (table below). Duration is free. **First request (with your API key):** ```bash curl -s https://api.proxies.sx/v1/gateway/credentials \ -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" # -> { "username": "psx_...", "httpProxy": "http://psx_...:PASS@gw.proxies.sx:7000", "socks5Proxy": "socks5://...:7001" } ``` Set a proxy password once (`PATCH /v1/account/proxy-password`), make sure the account has deposited GB, and connect. Full sequence: [The Standard Path](#the-standard-path-api-key--deposited-gb). No API key yet? [Step 1 of the walkthrough](#step-1-create-an-account--mint-an-api-key-one-time) takes two calls. Wallet-only with no account? Start at `GET /v1/x402/pool/pricing` in the [x402 section](#optional-pay-with-usdc-x402-no-account). > **Hierarchy:** this skill.md is the canonical Pool Gateway Access contract. If any other file disagrees with it, this file wins. If this file disagrees with the live API, the live API wins. ## Overview The Pool Gateway is ONE metered credential over the whole proxy network. You do not buy proxies one by one - you authenticate to `gw.proxies.sx` and declare pool/country/session/rotation per request inside the proxy username (the [DSL cheatsheet](#routing-parameters-username-dsl---full-cheatsheet)). The gateway meters every byte against your GB balance and refuses connections when it runs out - nothing to babysit. Three credential shapes work on the gateway (full table: [The Three Ways In](#the-three-ways-in-auth-paths)): 1. **Account credential (STANDARD - the main path):** username `psx_---...`, password = your proxy password. Budget = the GB deposited on your account. The whole surface is driven over REST with `X-API-Key: psx_...`. 2. **Reseller pak_ key:** a capped, metered sub-credential a reseller mints for each of their customers. 3. **x402 wallet-only (OPTIONAL):** pay USDC on-chain, get a pak_-backed credential + a session token - no account at all. - **Price:** $4.00/GB on both `peer` and `mbl` tiers, volume-discounted to $2.40/GB at 250 GB+ per purchase (table below) - **Duration:** FREE - you only pay for traffic - **Coverage:** one credential covers EVERY country with live stock - retarget via the username, no repurchase per country - **Protocols:** HTTP proxy on `gw.proxies.sx:7000` + SOCKS5 on `:7001` - both work for all three credential shapes (account, reseller-pak, and x402-minted), metered identically (fixed 2026-07-25; earlier v1 gated SOCKS5 to account/reseller-pak only) **Volume discount** (applied automatically per purchase; on the x402 path, top-ups are priced at the credential's mint-time $/GB - see [Top Up](#top-up-more-gb-andor-more-time)): | Purchase amount | Discount | Effective $/GB | |---|---|---| | 1-24 GB | 0% | $4.00 | | 25-49 GB | 10% | $3.60 | | 50-99 GB | 20% | $3.20 | | 100-249 GB | 30% | $2.80 | | 250+ GB | 40% | $2.40 | **The two tiers (peer is the flagship, mbl is the guaranteed backstop):** | Tier | Status | What it is | |------|--------|------------| | `peer` | **LIVE** | The flagship network - residential + mobile IPs connected in 150 countries (~127 with live stock), scaling toward millions of devices. Request `peer` for the widest coverage; the gateway probes peers and routes around dead ones, and you are metered per delivered byte, so broken peers cost you nothing | | `mbl` | LIVE | The supportive guaranteed-quality tier - carrier modems we operate end-to-end. Real 4G/5G carriers, 6 countries (US, GB, PL, FR, NL, GE), 10-15 Mbps, sub-1s TTFB, ~100% success | | `peer_mobile` | Disabled (x402 purchase returns 400) | Reserved for future mobile-peer separation. Use `peer` or `mbl`. | **Quality-tier semantics of minted `pak_*` credentials** (x402-minted and reseller-minted keys): - A `safe`-quality pak (the x402 `mbl` tier) is **quality-locked**: even if you write `peer` in the username, the gateway silently serves you from the carrier modems. That is by design - buy `mbl`/`safe` when you want the guaranteed tier and never a peer under you. - A `standard`-quality pak (the x402 `peer` tier) routes the pool token **as written** (`peer`, `mbl`, `any`, or `best`), so it can also target the 6 carrier-modem countries explicitly with `mbl-` at the same $4/GB. - **Account credentials are never quality-locked** - the pool token always routes as written. --- ## The Three Ways In (auth paths) The gateway at `gw.proxies.sx:7000` (HTTP) / `:7001` (SOCKS5) accepts three credential shapes. All three use the exact same [username DSL](#routing-parameters-username-dsl---full-cheatsheet) and [error codes](#error-handling). Path 1 is the standard and most-used; path 3 is the optional wallet-only alternative. | # | Path | Proxy username | Proxy password | How you get it | Protocols | |---|---|---|---|---|---| | 1 | **Account + API key + deposited GB (STANDARD)** | `psx_---...` (from `GET /v1/gateway/credentials`) | your **proxy password** (set via `PATCH /v1/account/proxy-password`, min 6 chars) | Sign up, mint an API key, deposit GB, set a proxy password - [full walkthrough](#the-standard-path-api-key--deposited-gb). NOTE: the account/login password does NOT work on the gateway - a separate proxy password is REQUIRED (no fallback) | HTTP :7000 + SOCKS5 :7001 | | 2 | **Reseller pak_ key** | the **reseller's** `psx_---...` | the `pak_*` value minted for that customer | Reseller mints capped keys at `POST /v1/reseller/pool-keys` (or via the `pool_mint_key` MCP tool) - [reference](#reseller-pak_-management-jwtapi-key--reseller-role) | HTTP :7000 + SOCKS5 :7001 | | 3 | **x402 wallet-only (OPTIONAL)** | `psx_---...` (returned at purchase) | the minted `pak_*` key | Pay USDC at `GET/POST /v1/x402/pool` - no account - [x402 section](#optional-pay-with-usdc-x402-no-account) | HTTP :7000 + SOCKS5 :7001 | All three are metered per GB at the same pricing. Account credentials draw from the account's deposited GB balance; `pak_*` keys (paths 2 and 3) carry their own GB cap and auto-suspend at the cap. --- ## Quick Reference | Action | Endpoint | Auth | |--------|----------|------| | Get your gateway credentials | `GET /v1/gateway/credentials` | `X-API-Key` or JWT | | Set/rotate the proxy password | `PATCH /v1/account/proxy-password` | `X-API-Key` (`account:write`) or JWT | | Bulk-build proxy URL strings | `POST /v1/gateway/pool/spawn` | `X-API-Key` (`ports:read`) or JWT (30/min) | | Check live stock | `GET /v1/gateway/pool/stock` | None (counts only, never IPs) | | Preview GB price | `GET /v1/billing/calculate-price?amount=N` | `X-API-Key` (`billing:read`) or JWT | | Buy GB from balance | `POST /v1/billing/purchase-traffic` | JWT (customers) / `billing:write` key (reseller/admin) | | Balance + available GB | `GET /v1/account/summary` | `X-API-Key` (`account:read`) or JWT | | My traffic + pool health | `GET /v1/gateway/pool/my-stats` | `X-API-Key` or JWT | | My live sessions | `GET /v1/gateway/pool/my-sessions` | `X-API-Key` or JWT | | Mint a customer pak_ key (reseller) | `POST /v1/reseller/pool-keys` | JWT/API key + reseller role | | x402: discover pricing | `GET /v1/x402/pool/pricing` | None | | x402: buy access | `GET` or `POST /v1/x402/pool` | x402 payment (10/min) | | x402: credit / top-up / usage / regenerate / re-emit | `/v1/x402/manage/pool/*` | `X-Session-Token` | | Use the proxy | `http://USERNAME:PASSWORD@gw.proxies.sx:7000` | Gateway credential | **Base URL:** `https://api.proxies.sx` **Gateway:** `gw.proxies.sx:7000` (HTTP proxy, CONNECT supported); `gw.proxies.sx:7001` (SOCKS5 - works for all credential shapes, including x402-minted) --- ## The Standard Path: API Key + Deposited GB The main way to use the Pool Gateway. No crypto involved: an account, an API key for automation, deposited GB as the budget, one proxy password for the gateway. Everything after the one-time key mint is a plain REST call with `X-API-Key: psx_...`. ### Step 1: Create an account + mint an API key (one-time) Sign up, open the verification link emailed to you (valid 24 hours; from a script: `GET /v1/login/verify-email?token=`, which also returns the first `access_token`), then sign in; sign-in answers 401 until the email is verified. Or use the portal at https://client.proxies.sx: ```bash curl -s -X POST https://api.proxies.sx/v1/login/signup \ -H 'Content-Type: application/json' \ -d '{"email":"agent@example.com","password":"YOUR_LOGIN_PASSWORD"}' curl -s -X POST https://api.proxies.sx/v1/login/signin \ -H 'Content-Type: application/json' \ -d '{"email":"agent@example.com","password":"YOUR_LOGIN_PASSWORD"}' # -> { "access_token": "eyJ..." } (JWT) ``` Mint the API key - this is a **JWT-only** step (by design, you cannot mint a key with a key): ```bash curl -s -X POST https://api.proxies.sx/v1/api-keys \ -H "Authorization: Bearer $JWT" \ -H 'Content-Type: application/json' \ -d '{"name":"pool-agent","scopes":["ports:read","ports:write","billing:read","account:read","account:write","traffic:read"]}' # -> { "apiKey": "psx_<32 hex chars>", "keyInfo": { ... } } ``` **Key facts:** the plain key is returned **once** - save it. Format `psx_` + 32 hex chars, max 5 active keys per account, per-key rate limit default 100 req/min (configurable 10-1000). Send it as `X-API-Key: psx_...` or `Authorization: ApiKey psx_...`. If you omit `scopes`, the key defaults to `ports:read, account:read, traffic:read`. Scopes only constrain API-key calls - your JWT session is never scope-restricted. ### Step 2: Deposit GB (money in, GB on the account) Top up your balance in the portal (https://client.proxies.sx - Billing) by card (Stripe) or hosted crypto checkout. The Stripe endpoints (`POST /v1/stripe/create-payment-intent`, saved-card top-up) are JWT-only. Preview the GB price (volume discount applies automatically): ```bash curl -s 'https://api.proxies.sx/v1/billing/calculate-price?amount=50' \ -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" # -> { "basePrice": 4, "discountPercent": 20, "pricePerGB": 3.20, "totalPrice": 160, "amount": 50 } ``` Convert balance to GB: ```bash curl -s -X POST https://api.proxies.sx/v1/billing/purchase-traffic \ -H "Authorization: Bearer $JWT" \ -H 'Content-Type: application/json' \ -d '{"amount": 50}' # 400 "Insufficient balance. Required: X, Available: Y" if the balance doesn't cover it ``` > **Scope note:** customer API keys cannot carry `billing:write` (purchases are UI/JWT-only for customers, by design). Buy GB in the portal or with your JWT session; reseller and admin keys CAN carry `billing:write` and automate this call. Check what you have at any time: ```bash curl -s https://api.proxies.sx/v1/account/summary -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" # -> { "balance": ..., "shared": { "trafficGB": { "total": 50, "used": 0, "available": 50 } }, ... } ``` Deposited GB **is** the gateway budget: at every proxy connect the gateway checks `purchased GB - used GB > 0` and rejects with `Insufficient traffic. Please purchase more shared traffic.` when it hits zero. ### Step 3: Set the proxy password (REQUIRED - no fallback) The gateway does NOT accept your account/login password. A separate proxy password is required: ```bash curl -s -X PATCH https://api.proxies.sx/v1/account/proxy-password \ -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" \ -H 'Content-Type: application/json' \ -d '{"proxyPassword":"YOUR_PROXY_PASSWORD"}' # -> { "message": "Proxy password updated successfully", "proxyUsername": "psx_" } ``` Min 6 chars. Retrieve it later with `GET /v1/account/proxy-password`; rotate it any time with the same PATCH (your login password is untouched - that separation is the point). ### Step 4: Check live stock (no auth) ```bash curl -s https://api.proxies.sx/v1/gateway/pool/stock # Routable endpoint COUNTS per pool + country. Never exposes IPs. curl -s 'https://api.proxies.sx/v1/gateway/pool/stock/carriers?country=US&pool=peer' # Per-country carrier/ASN/ipType breakdown ``` Prefer countries with routable depth >= 2 in your chosen pool ([why](#choosing-a-network-mbl-vs-peer-vs-bestany)). ### Step 5: Generate N Ready Proxy Strings (spawn) `POST /v1/gateway/pool/spawn` builds 1-1000 ready-to-use proxy URLs from options - pure string construction, no billing, no DB writes (metering happens at connect time), so spawning costs nothing: ```bash curl -s -X POST https://api.proxies.sx/v1/gateway/pool/spawn \ -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" \ -H 'Content-Type: application/json' \ -d '{"count":10,"country":"us","pool":"mbl","rotation":"sticky","sessionType":"unique","sessionPrefix":"batch"}' ``` **Response:** ```json { "count": 10, "host": "gw.proxies.sx", "httpPort": 7000, "socksPort": 7001, "pool": "mbl", "country": "us", "rotation": "sticky", "proxies": [ "http://psx_YOUR_UID-mbl-us-sid-batch1-rot-sticky:@gw.proxies.sx:7000", "http://psx_YOUR_UID-mbl-us-sid-batch2-rot-sticky:@gw.proxies.sx:7000", "... 8 more ..." ] } ``` Options: `count` (1-1000, required), `country` (`us`|...|`any`), `pool` (`mbl`|`peer`|`any`), `rotation` (`sticky`|`hard`|`auto5/10/20/60`|`ondemand`, default `auto10`), `sessionType` (`unique`|`same`|`none`, default `unique`), `sessionPrefix`, `carrier`, `asn`, `failover`, `protocol` (`http`|`socks5`), `format` (`url`|`hostport`|`authhost`). Rate limit 30/min. The password field is the literal placeholder `` - this endpoint never returns your actual password. Substitute the password from Step 3 (or retrieve it any time with `GET /v1/account/proxy-password`). You can also hand-build usernames with the [DSL cheatsheet](#routing-parameters-username-dsl---full-cheatsheet) - spawn is a convenience, not a requirement. ### Step 6: Connect ```bash # HTTP proxy curl -x "http://psx_YOUR_UID-mbl-us-sid-batch1-rot-sticky:YOUR_PROXY_PASSWORD@gw.proxies.sx:7000" \ https://api.ipify.org # SOCKS5 works on the account credential curl -x "socks5://psx_YOUR_UID-mbl-us-sid-batch1-rot-sticky:YOUR_PROXY_PASSWORD@gw.proxies.sx:7001" \ https://api.ipify.org # Retarget any country with the SAME credential - just edit the token curl -x "http://psx_YOUR_UID-peer-de-sid-batch1-rot-sticky:YOUR_PROXY_PASSWORD@gw.proxies.sx:7000" \ https://api.ipify.org ``` ### Step 7: Monitor, manage, refill ```bash # Your traffic totals + aggregated pool health curl -s https://api.proxies.sx/v1/gateway/pool/my-stats -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" # -> { "myTotalGB": ..., "myActiveConnections": ..., "poolOnlineDevices": ..., "poolHealthScore": ... } # Live sessions (traffic, exit IP, rotation, expiry) curl -s https://api.proxies.sx/v1/gateway/pool/my-sessions -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" # Close one / all sessions (needs ports:write) curl -s -X DELETE https://api.proxies.sx/v1/gateway/pool/my-sessions/SESSION_KEY -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" curl -s -X DELETE https://api.proxies.sx/v1/gateway/pool/my-sessions -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" # Per-period usage breakdown curl -s 'https://api.proxies.sx/v1/account/usage?period=30d' -H "X-API-Key: psx_YOUR_ACCOUNT_KEY" ``` When the deposited GB runs out the gateway rejects connects with `Insufficient traffic. Please purchase more shared traffic.` - repeat Step 2. ### The whole loop, compact ``` STEP 1 One-time POST /v1/login/signin -> JWT -> POST /v1/api-keys -> psx_ key (save it) STEP 2 Fund portal top-up -> POST /v1/billing/purchase-traffic {"amount": N} (JWT/portal) STEP 3 Password PATCH /v1/account/proxy-password (X-API-Key) STEP 4 Stock GET /v1/gateway/pool/stock (no auth) STEP 5 Spawn POST /v1/gateway/pool/spawn {"count":10,...} (X-API-Key) STEP 6 Use curl -x http://psx_---sid-..:PROXY_PASS@gw.proxies.sx:7000 STEP 7 Monitor GET /v1/account/summary + /v1/gateway/pool/my-stats + my-sessions (X-API-Key) Refill: repeat STEP 2 when available GB approaches 0. ``` ### Public endpoints (no auth - counts only, never exit IPs) | Endpoint | Purpose | |---|---| | `GET /v1/gateway/pool/stock` | Routable endpoint counts per pool + country (0-stock countries omitted; ETag/304, ~30s cache) | | `GET /v1/gateway/pool/stock/carriers?country=US&pool=peer` | Per-country carrier/ASN/ipType breakdown (counts only) | | `GET /v1/gateway/pool/availability` | Online/total/routable device counts per country, split modem vs peer | | `GET /v1/gateway/pool/capacity` | Active vs max connection capacity + utilization per country | | `GET /v1/gateway/incidents` | Current stock-derived incidents (severity, message, since) | | `GET /v1/gateway/health` | Gateway-auth service liveness | ### Account self-service reference (JWT or `X-API-Key`) | Endpoint | Purpose | |---|---| | `GET /v1/gateway/credentials` | Your `psx_` proxy username + ready HTTP/SOCKS5 connect strings (password never returned here - retrieve it via `GET /v1/account/proxy-password`) | | `PATCH /v1/account/proxy-password` | Set/rotate the separate proxy password (min 6 chars, scope `account:write`). Required - the account login password does NOT work on the gateway | | `GET /v1/account/proxy-password` | Retrieve the current proxy password + username (scope `account:read`) | | `GET /v1/account/summary` | Balance + shared slots/GB totals + alerts (scope `account:read`) | | `GET /v1/account/usage?period=7d\|30d\|90d` | Per-port traffic breakdown (scope `traffic:read`) | | `GET /v1/billing/pricing` | Pricing, volume discounts, tiers, your tier info (scope `billing:read`) | | `GET /v1/billing/calculate-price?amount=N` | Exact price preview with volume discount (scope `billing:read`) | | `POST /v1/billing/purchase-traffic` | Convert balance to GB - JWT for customers; `billing:write` keys (reseller/admin) can automate | | `POST /v1/gateway/pool/spawn` | Bulk-build 1-1000 ready proxy URL strings (options in [Step 5](#step-5-generate-n-ready-proxy-strings-spawn)). Pure string construction; password placeholder ``. 30/min | | `GET /v1/gateway/pool/my-stats` | Your traffic totals + aggregated pool health | | `GET /v1/gateway/pool/my-sessions?pakId=` | Your live gateway sessions (traffic, exit IP, rotation, expiry); optional `pakId` scope for resellers | | `DELETE /v1/gateway/pool/my-sessions/:sessionKey` | Close one session (ownership-checked) | | `DELETE /v1/gateway/pool/my-sessions` | Close all your sessions (idempotent) | ### Reseller pak_ management (JWT/API key + reseller role) A pak_ key is a capped, metered sub-credential: your customer connects with YOUR `psx_-...` DSL username and the `pak_*` value as password. `qualityTier: 'safe'` locks the key to carrier modems (the gateway rewrites `peer-*` -> `mbl-*`); `'standard'` routes as written. | Endpoint | Purpose | |---|---| | `POST /v1/reseller/pool-keys` | Mint: `{label (required), trafficCapGB? (1-100000\|null=unlimited), expiresAt? (ISO\|null), qualityTier? (safe\|standard)}`. Fresh-auth gated for JWT callers (`X-Confirm-Password` or JWT <5min; API-key callers bypass). Supports `Idempotency-Key` header. 30/min | | `GET /v1/reseller/pool-keys` | List your keys (response carries pak_ secrets - `Cache-Control: private, no-store`) | | `GET /v1/reseller/pool-keys/:keyId` | One key | | `POST /v1/reseller/pool-keys/:keyId/reveal` | Unmask the full pak_ (audit-logged `reveal` event). 30/min | | `PATCH /v1/reseller/pool-keys/:keyId` | Update label/enabled/cap/expiry/qualityTier (null clears cap/expiry). Prefer /topup for cap extensions (race-free) | | `POST /v1/reseller/pool-keys/:keyId/topup` | Atomic `{addTrafficGB? (1-100000), extendDays? (1-1825)}` - `$inc` on the cap; extends expiry from max(now, current), never shortens | | `POST /v1/reseller/pool-keys/:keyId/regenerate` | Rotate the pak_ secret (old value dies immediately, same key id). Fresh-auth gated | | `DELETE /v1/reseller/pool-keys/:keyId` | Delete (soft, audited) | | `GET /v1/reseller/pool-keys/:keyId/usage?days=30` | Daily in/out MB series per key (gap-filled zeroes; days max 365) - per-customer billing chart | | `GET /v1/reseller/pool-keys/audit` and `/:keyId/audit` | Forensic audit log: create/update/topup/regenerate/reveal/delete/gateway_auth_success/gateway_auth_failure/auto_suspended_cap_exceeded/auto_suspended_expired, newest first | Keys auto-suspend at their GB cap (`enabled` -> false, `E_CAP_EXCEEDED` at the gateway) and on expiry. --- ## Routing Parameters (Username DSL) - full cheatsheet The same parser serves all three auth paths. The username is a `-`-delimited token string - it is lowercased and split on `-`, so no token value may itself contain a `-` (write `tmobile`, never `t-mobile`). Positional fields first, then optional tokens in any order (each token consumes `token value`): ``` --[-- ...] ``` | Position | Field | Values | Default | |---|---|---|---| | 1 | accountId | your `psx_*` username part (required - this is the real auth gate) | required | | 2 | pool | `mbl` \| `peer` \| `any` \| `best` | `any` if omitted/unrecognized | | 3 | country | 2-letter ISO code or `any` | `any` | **Optional tokens:** | Token | Example | Meaning | |-------|---------|---------| | `sid` | `-sid-myagent01` | Session id, `[a-z0-9_]` (1-64 accepted by the parser; use 8-64 to also satisfy the x402 purchase endpoint). Same sid returns to the same endpoint. REQUIRED for `sticky`/`auto*` to persist across connections | | `rot` | `-rot-sticky` | Rotation mode (table below). If you omit the token entirely, the gateway default is `auto10`. **Careful:** the x402 purchase endpoint hands back a starting username built with `rot=sticky`, so an x402-minted credential holds its exit while a hand-written username without `-rot-` moves every ~10 min. If your IP started changing after you edited the username, this is why — put `-rot-sticky-` back | | `city` | `-city-newyork` | Soft preference, sanitized, max 64 chars | | `state` | `-state-il` | Soft US-state/region preference (peer network): prefers a live endpoint in that state, silently falls back to any same-country endpoint. Added Aug 2026. | | `carrier` | `-carrier-tmobile` | Soft preference, sanitized, max 64 chars | | `iptype` | `-iptype-residential` | Hard device-class filter: `mobile` \| `residential` \| `datacenter` (aliases: `mbl/cell/cellular` -> mobile, `resi/res/home` -> residential, `dc/hosting/server` -> datacenter) | | `isp` | `-isp-spectrum` | Hard filter: slugified case-insensitive prefix match on the exit's ISP brand | | `asn` | `-asn-7018` | Hard filter: exact ASN match, digits only, max 7 | | `pin` | `-pin-device-abc123` | Pin an exact endpoint - takes TWO parts: `port`\|`device` + id | | `strict` | `-rot-sticky-strict` | Bare flag (no value). `-rot-sticky-strict` parses naturally as `rot=sticky` + `strict`. Hardens sticky selection: weights IP-stability heavily and enforces a hard minimum-stability floor - best for login/cookie/2FA flows. A no-op for `auto*`/`ondemand` | | `failover` | `-failover-samecarrier` | If the exit dies mid-request, where to retry: `any`, `samecountry` (default), `samecarrier`, `samenode` (same relay server), `strict` (fail instead of retrying elsewhere) | | `ttl` | `-ttl-7200` | Session-row TTL in seconds, clamped 60-2592000, default 3600. NOT an IP-hold guarantee | | *(unknown)* | `-session-x` | Silently SKIPPED (forward-compat). **`-session-` does NOTHING** - the sticky token is `sid`, not `session` | **Self-healing parser (Postel's Law):** the parser NEVER rejects a bad optional token - it sanitizes (`[a-z0-9_]`, length-capped), aliases, and defaults, then routes, recording each fix in a corrections log. The only hard failures are a missing username or one over 256 chars. The flip side: a typo won't error - it will silently route differently than you intended. Build usernames from constants, not free-text interpolation. **Aliases the parser understands** (so agents don't have to be perfect): pool - `mobile/modem/cell/cellular/lte/4g/5g/sim` -> `mbl`, `residential/resi/res/home/household` -> `peer`, `all/mixed` -> `any`, `premium/fast/quality/top` -> `best`. Country - `usa/america` -> `us`, `uk/britain/england` -> `gb`, `germany/ger/deu` -> `de`, `france` -> `fr`, `spain` -> `es`, `poland` -> `pl`, `netherlands/holland` -> `nl`, `georgia/geo` -> `ge`. Rotation - `auto/rotate/rotating/rotation` -> `auto10`, `static/stick/pinned/pin/stable/fixed/persistent/keep` -> `sticky`. > **The Germany trap:** `germany` aliases to `de` - and `de` has NO mbl stock (`ge` is Georgia). `mbl-de` will fail with `E_NO_STOCK_COUNTRY`; for Germany use `peer-de`. **Rotation modes:** | Mode | Behavior | |------|----------| | `sticky` | Pin one endpoint for the session (gateway picks the most IP-stable one). Recommended default | | `sticky-strict` | Parses as `rot=sticky` + the bare `strict` flag (the internal hyphen is safe - the DSL splits on `-`). Hardened IP-stability selection for login/cookie/2FA flows. Needs a `-sid-` | | `hard` | Pins like `sticky`. It does NOT mean a new IP per request - a true carrier-IP reset only exists on the dedicated-port product's rotate URL | | `auto5` / `auto10` / `auto20` / `auto60` | Switch to a different endpoint every 5/10/20/60 minutes (`auto10` is the gateway default when `rot` is omitted) | | any other `auto` | The gateway snaps it to the nearest of 5/10/20/60 (e.g. `auto30` -> `auto20`) and records the fix in its corrections log - do not invent intervals | | `ondemand` | Re-pick an endpoint on each new connection | > **Sticky pins the MODEM, not the IP.** Mobile carriers re-issue NAT egress IPs on their own cadence, so a perfectly pinned modem can still surface different exit IPs. If your workflow needs one immutable IP, use a residential `peer` exit (home-ISP IPs are stable for hours-to-days) or the dedicated port product. --- ## Choosing a Network: `mbl` vs `peer` vs `best`/`any` The pool token is the 2nd token in the username. Both pools cost the same $4/GB - the difference is stability vs breadth. | Pool | What it is | Countries | When to use | |---|---|---|---| | `mbl` | ProxySmart carrier modems - ultra-stable, real mobile carriers | 6: `us`, `gb`, `fr`, `nl`, `pl`, `ge` (**GE = Georgia, NOT Germany**) | Anything that must not drop mid-request: checkout flows, logins, long downloads, scraping sessions with cookies | | `peer` | The flagship network - residential + mobile peer devices | ~127 countries with live stock | Breadth: countries mbl doesn't have, IP diversity, volume scraping where a retry is cheap | | `best` / `any` | Gateway picks across both pools | union | Convenience default - but inherits peer's failure modes in countries where peers dominate | **Hard-won lesson (real production incident):** a reseller ran `best`/GB traffic and their "proxy kept dying after a few seconds." Nothing was wrong with their account - `best` was routing them onto flaky GB *peer* devices that accept the CONNECT then drop the TLS tunnel (the known `tls_dropped` peer-SDK pattern). The fix was one token: `best` -> `mbl-gb` (stable UK carrier modems). Every session became solid. **Rules for agents:** - Need **stability** -> pick `mbl-` explicitly (if the country is one of the 6). - Need **breadth or volume** -> use `peer` or `best`, wrap every request in retry-with-backoff, and treat a dropped tunnel as normal (the gateway probes peers and routes around dead ones, but some slip through - and you are metered per delivered byte, so broken peers cost you nothing). - Check `GET /v1/gateway/pool/stock` first and prefer countries with routable depth >= 2 in your chosen pool; depth 1 means any single device failure = `E_NO_STOCK_COUNTRY`. --- ## Optional: Pay with USDC (x402, No Account) Everything in this section is the **wallet-only alternative** for agents that cannot hold an account: pay USDC on-chain (Base or Solana), retry the request with the transaction hash, and receive a working proxy credential plus a session token (`x402s_*`) for self-service management (credit, top-up, usage, regenerate). If you can hold an account, use [the standard path](#the-standard-path-api-key--deposited-gb) instead - it is the main, recommended path and needs no crypto or wallet management. How it works under the hood: your payment mints a GB-capped pak key (`pak_*`) - it goes in the proxy **password** field. The GB cap IS your credit envelope - the gateway meters every byte, and the credential auto-suspends when the cap is reached. Top up with more USDC to keep going. - **Payment:** USDC on Solana (~400ms settlement) or Base (~2s settlement) - **Price:** same $4.00/GB ladder as the standard path; minimum purchase 0.1 GB ($0.40) - **Duration:** FREE - default 30 days, maximum 90 days - **Protocol:** HTTP proxy on `gw.proxies.sx:7000` and SOCKS5 on `:7001`, both metered identically (fixed 2026-07-25) **First request (no auth, no payment):** ```bash curl -s "https://api.proxies.sx/v1/x402/pool/pricing" ``` Then request `GET /v1/x402/pool` without payment - the HTTP 402 response IS the catalog (exact amount, recipient, asset). Pay USDC on-chain, retry the same request with `Payment-Signature: `, and you receive credentials. ### Complete Purchase Workflow #### Step 1: Discover Pricing ```http GET https://api.proxies.sx/v1/x402/pool/pricing ``` **Response (live, abbreviated):** ```json { "product": "pool", "tiers": [ { "tier": "mbl", "pricePerGB": 4, "currency": "USDC", "minPurchaseGB": 0.1, "quality": "production tier - ProxySmart modems, 6 countries, 10-15 Mbps, sub-1s TTFB, 100% success", "allowedIpTypes": ["mobile"] }, { "tier": "peer", "pricePerGB": 4, "currency": "USDC", "minPurchaseGB": 0.1, "quality": "flagship tier - mobile/residential/datacenter peers, ~127 countries with live stock; the gateway probes and routes around dead peers, metered so you only pay for bytes delivered", "allowedIpTypes": ["mobile", "residential", "datacenter", "unknown"] } ], "defaultTier": "mbl", "durationFree": true, "maxDurationSeconds": 7776000, "stockUrl": "https://api.proxies.sx/v1/gateway/pool/stock", "usernameDsl": "psx_-{pool}-{country}[-sid-{8-64 a-z0-9_}][-rot-{sticky|hard|auto5|auto10|auto20|auto60|ondemand}][-carrier-..][-city-..]", "networks": [ { "network": "base", "usdcAddress": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "recipientAddress": "0xF8cD900794245fc36CBE65be9afc23CDF5103042" }, { "network": "solana", "usdcAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "recipientAddress": "6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv" } ] } ``` The `usernameDsl` string in the response is abbreviated - the gateway parser accepts the [full token set](#routing-parameters-username-dsl---full-cheatsheet) (`failover`, `ttl`, `iptype`, `isp`, `asn`, `pin`, `strict` too). Check live per-country stock BEFORE buying for a specific country (the catalog's country list can drift from live stock): ```bash curl -s https://api.proxies.sx/v1/gateway/pool/stock # Returns endpoint COUNTS per pool + country. Never exposes IPs. ``` #### Step 2: Request Without Payment (the 402 IS the catalog) ```bash # Guaranteed carrier-modem tier (default): curl -s "https://api.proxies.sx/v1/x402/pool?tier=mbl&country=us&traffic=1" # Flagship peer tier (~127 countries with live stock) - same price, same flow: curl -s "https://api.proxies.sx/v1/x402/pool?tier=peer&country=de&traffic=1" ``` You get an HTTP 402 with everything needed to pay: ```json { "x402Version": 1, "error": "Payment required to access this resource", "accepts": [ { "scheme": "exact", "network": "base", "maxAmountRequired": "4000000", "payTo": "0xF8cD900794245fc36CBE65be9afc23CDF5103042", "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "description": "Pool Gateway mbl access: 1 GB at $4/GB = $4 USDC. One credential, every country in the tier, metered + capped." }, { "scheme": "exact", "network": "solana", "maxAmountRequired": "4000000", "payTo": "6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv", "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" } ], "pool": { "tier": "mbl", "pricePerGB": 4, "trafficGB": 1, "amountUSDC": 4, "stockUrl": "https://api.proxies.sx/v1/gateway/pool/stock", "management": { "credit": "GET /v1/x402/manage/pool/credit", "topup": "POST /v1/x402/manage/pool/topup", "usage": "GET /v1/x402/manage/pool/usage", "regenerate": "POST /v1/x402/manage/pool/regenerate", "connection": "GET /v1/x402/manage/pool/connection" } } } ``` **IMPORTANT - which 402 fields to trust:** - `accepts[].maxAmountRequired` (micro-USDC, 6 decimals) is the authoritative price. `accepts[].payTo` + `accepts[].asset` are the authoritative recipient + token. - The `pool` block is the authoritative pool catalog. - **Ignore `accepts[].outputSchema`** - it is inherited from the dedicated-port product and is WRONG for pool purchases (it claims `tier: shared`, `duration` required, a `socksPort` output, and a 30-day max). The real pool parameters are in the table below. **Purchase parameters** (query string on GET, JSON body on POST - both merged): | Param | Required | Values | Default | |-------|----------|--------|---------| | `tier` | No | `mbl` (6-country carrier modems) or `peer` (flagship, ~127 countries with live stock) - both $4/GB. `peer_mobile` is disabled (400) | `mbl` | | `country` | No | 2-letter ISO code or `any`. Only sets the country token in your STARTING username - you can retarget any country later | `any` | | `traffic` | Yes | GB, 0.1 to 1000 | - | | `duration` | No | Seconds, up to 7776000 (90 days). FREE - does not change the price | 2592000 (30 days) | | `sid` | No | Session id, 8-64 chars `[a-z0-9_]`. Auto-generated if absent or invalid | auto | | `rot` | No | `sticky`, `hard`, `auto5`, `auto10`, `auto20`, `auto60`, `ondemand` | `sticky` | `traffic` is priced on the volume-discount ladder above - e.g. `traffic=250` prices at $2.40/GB ($600), not $4/GB. > **sid length, reconciled:** this purchase endpoint documents `sid` as 8-64 chars and auto-replaces anything shorter; the gateway parser itself accepts any 1-64 char `[a-z0-9_]` sid at connection time (values are sanitized, never rejected). Use 8-64 chars to satisfy both. #### Step 3: Pay USDC On-Chain Send the exact `maxAmountRequired` (micro-USDC) to the `payTo` address of your chosen network. A 2% underpay tolerance is allowed (gas dust / rounding). The transaction must be a direct on-chain USDC transfer, confirmed, and less than 24 hours old. | Network | Recipient | USDC Contract / Mint | Settlement | |---------|-----------|----------------------|------------| | Base | `0xF8cD900794245fc36CBE65be9afc23CDF5103042` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | ~2s, ~$0.01 gas | | Solana | `6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | ~400ms, ~$0.0001 gas | Example sends ($4.00 = 4000000 micro-USDC): ```bash # Base (any EVM tooling works - this is foundry's cast) cast send 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \ "transfer(address,uint256)" \ 0xF8cD900794245fc36CBE65be9afc23CDF5103042 4000000 \ --rpc-url https://mainnet.base.org --private-key $PRIVATE_KEY # Save the printed transaction hash (0x...) # Solana (spl-token CLI; amount is in whole USDC) spl-token transfer EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v 4 \ 6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv \ --fund-recipient --allow-unfunded-recipient # Save the printed transaction signature (base58) ``` **Payment rules (verified on-chain by the server):** - The recipient AND the USDC asset are pinned - a payment to any other address or in any other token is rejected. - Only direct on-chain transactions are accepted. Signed-intent / facilitator payloads are rejected - settle on-chain and send the tx hash. - Each transaction hash mints exactly ONE credential. The same hash can NOT also buy a dedicated port (`/v1/x402/proxy`) - that returns 409. #### Step 4: Retry With the Payment Proof Send the same request with the `Payment-Signature` header (aliases `X-Payment-Signature` and `Payment` also work on this endpoint): ```bash # Base curl -s "https://api.proxies.sx/v1/x402/pool?tier=mbl&country=us&traffic=1&sid=myagent01&rot=sticky" \ -H "Payment-Signature: 0xYOUR_BASE_TX_HASH" # Solana curl -s "https://api.proxies.sx/v1/x402/pool?tier=mbl&country=us&traffic=1&sid=myagent01&rot=sticky" \ -H "Payment-Signature: YOUR_SOLANA_TX_SIGNATURE" ``` **Response (HTTP 200):** ```json { "product": "pool", "proxy": { "host": "gw.proxies.sx", "httpPort": 7000, "username": "psx_x402pool-mbl-us-sid-myagent01-rot-sticky", "password": "pak_a1b2c3d4e5f6...", "http": "http://psx_x402pool-mbl-us-sid-myagent01-rot-sticky:pak_a1b2c3d4e5f6...@gw.proxies.sx:7000", "socks5": "socks5://psx_x402pool-mbl-us-sid-myagent01-rot-sticky:pak_a1b2c3d4e5f6...@gw.proxies.sx:7001", "usernameTemplate": "psx_x402pool-{pool}-{country}[-sid-{8-64 a-z0-9_}][-rot-{sticky|hard|auto5|auto10|auto20|auto60|ondemand}][-city-..][-carrier-..]", "allowed": { "tier": "mbl", "ipTypes": ["mobile"], "countries": "any with stock - see stockUrl" } }, "credit": { "allocatedGB": 1, "usedGB": 0, "remainingGB": 1, "expiresAt": "2026-07-12T00:00:00.000Z", "enabled": true }, "sessionToken": "x402s_abc123...", "manage": { "credit": "GET /v1/x402/manage/pool/credit", "topup": "POST /v1/x402/manage/pool/topup", "usage": "GET /v1/x402/manage/pool/usage", "regenerate": "POST /v1/x402/manage/pool/regenerate", "connection": "GET /v1/x402/manage/pool/connection" }, "stockUrl": "https://api.proxies.sx/v1/gateway/pool/stock", "quality": { "tier": "mbl", "story": "production tier - ProxySmart modems, 6 countries, 10-15 Mbps, sub-1s TTFB, 100% success" }, "caveats": [ "sticky pins the MODEM, not the IP - carrier NAT may re-issue exit IPs; for a held IP use the dedicated port product (/v1/x402/proxy)", "sticky/auto* require -sid- (8-64 chars a-z0-9_) to persist across connections", "no token value may contain '-' (username is lowercased and split on '-')", "mbl tier: peer routes in the username are silently served from modems (quality-tier safe rewrite) - by design", "HTTP :7000 and SOCKS5 :7001 both work; GB is metered identically on either", "cap suspension lands within ~5-35s of the GB cap; no refunds of unused GB" ], "payment": { "txHash": "0x...", "network": "base", "amountUSDC": 4 } } ``` (The `usernameTemplate` string is abbreviated - the [full token set](#routing-parameters-username-dsl---full-cheatsheet) also works.) **Save THREE things:** 1. `proxy.password` (the `pak_*` key) - your proxy password 2. `sessionToken` (`x402s_*`) - required for ALL manage endpoints 3. `payment.txHash` - your last-resort recovery handle **Idempotent retries:** if the response is lost (timeout, crash), retry the exact same call with the same `Payment-Signature`. The server recognizes the already-redeemed transaction and re-emits the SAME credentials and session token. You are never double-charged. #### Step 5: Connect Through the Gateway The password is always your `pak_*` key; the username follows the shared [DSL cheatsheet](#routing-parameters-username-dsl---full-cheatsheet): ``` psx_x402pool-{pool}-{country}[-sid-{name}][-rot-{mode}][-city-{city}][-carrier-{carrier}][-failover-{policy}][-ttl-{seconds}] ``` ```bash # Use the credential exactly as returned curl -x "http://psx_x402pool-mbl-us-sid-myagent01-rot-sticky:pak_YOUR_KEY@gw.proxies.sx:7000" \ https://api.ipify.org # Retarget a different country - SAME credential, no repurchase. # Just edit the country token. The live set is whatever stockUrl reports - # check it first. As of last edit: us, gb, pl, fr, nl, ge (ge = Georgia, not Germany): curl -x "http://psx_x402pool-mbl-nl-sid-myagent01-rot-sticky:pak_YOUR_KEY@gw.proxies.sx:7000" \ https://api.ipify.org # Rotate every 10 minutes instead of pinning: curl -x "http://psx_x402pool-mbl-us-sid-myagent01-rot-auto10:pak_YOUR_KEY@gw.proxies.sx:7000" \ https://api.ipify.org # Parallel isolated sessions - one sid per worker: curl -x "http://psx_x402pool-mbl-us-sid-worker_001-rot-sticky:pak_YOUR_KEY@gw.proxies.sx:7000" \ https://api.ipify.org ``` > **HTTP and SOCKS5 both work for this credential.** Connect to `gw.proxies.sx:7000` as an HTTP proxy (CONNECT tunneling works for HTTPS targets) or `gw.proxies.sx:7001` as SOCKS5 - GB is metered identically on either. (Fixed 2026-07-25; earlier v1 responses advertised a null SOCKS5 field and rejected x402-minted credentials on :7001 - that restriction is gone.) ### Manage Your Credential All management endpoints authenticate with the session token from the purchase response: ``` Header: X-Session-Token: x402s_... ``` #### Check Credit ```bash curl -s https://api.proxies.sx/v1/x402/manage/pool/credit \ -H "X-Session-Token: x402s_YOUR_TOKEN" ``` ```json { "tier": "mbl", "allocatedGB": 1, "usedGB": 0.2143, "remainingGB": 0.7857, "enabled": true, "expiresAt": "2026-07-12T00:00:00.000Z", "sessionToken": "x402s_..." } ``` Metering is read-through and live: `remainingGB = allocatedGB - usedGB`. When `usedGB` reaches the cap, `enabled` flips to `false` automatically (within ~5-35s) and the gateway starts rejecting auth. Top up to re-enable. #### Re-Emit Connection Details Lost the password but kept the session token? This re-emits the full purchase response (credentials, username template, credit, caveats): ```bash curl -s https://api.proxies.sx/v1/x402/manage/pool/connection \ -H "X-Session-Token: x402s_YOUR_TOKEN" ``` #### Usage History ```bash curl -s "https://api.proxies.sx/v1/x402/manage/pool/usage?days=30" \ -H "X-Session-Token: x402s_YOUR_TOKEN" # Response: { "tier": "mbl", "days": 30, "usage": [ per-day traffic series ] } # days: 1-365, default 30 ``` #### Regenerate the Password If the `pak_*` key leaks, mint a new secret. The old password stops working immediately; the username and remaining credit are unchanged. Rate limited to 3/hour. ```bash curl -s -X POST https://api.proxies.sx/v1/x402/manage/pool/regenerate \ -H "X-Session-Token: x402s_YOUR_TOKEN" # Response: full connection shape with the NEW pak_ password ``` #### Top Up (more GB and/or more time) Traffic costs money, priced at the credential's original (mint-time) $/GB - the volume-discount ladder is NOT re-applied to the top-up size. A credential minted at 1 GB ($4/GB) pays $4/GB on every top-up, even `addTrafficGB: 250` ($1,000); one minted at 250+ GB ($2.40/GB) tops up at $2.40/GB. Buying big up front is the only way to lock the discount. Duration extension is free. A successful traffic top-up also re-enables a cap-suspended credential. ```bash # 1. Ask without payment -> 402 tells you the exact amount curl -s -X POST https://api.proxies.sx/v1/x402/manage/pool/topup \ -H "X-Session-Token: x402s_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"addTrafficGB": 2}' # 402: "Top-up requires payment: 2GB at $4/GB = $8 USDC. Send USDC then retry with Payment-Signature." # 2. Send USDC on-chain (same recipients as the purchase), then retry with the NEW tx hash curl -s -X POST https://api.proxies.sx/v1/x402/manage/pool/topup \ -H "X-Session-Token: x402s_YOUR_TOKEN" \ -H "Payment-Signature: NEW_TX_HASH" \ -H "Content-Type: application/json" \ -d '{"addTrafficGB": 2, "addDurationSeconds": 2592000}' # Response: updated credit object # Duration-only extension is FREE - no payment header needed: curl -s -X POST https://api.proxies.sx/v1/x402/manage/pool/topup \ -H "X-Session-Token: x402s_YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"addDurationSeconds": 2592000}' ``` **Top-up rules:** - Each tx hash is redeemable exactly once. Reusing your purchase hash or a previous top-up hash returns 409 and adds nothing. - Same 2% underpay tolerance. Underpaid returns 400 with the exact micro-USDC amount needed. - `addDurationSeconds` is clamped to 90 days per call. Rate limited to 5/min. - This endpoint reads the payment proof from the `Payment-Signature` header only. ### End-to-End Worked Example (x402) The whole wallet-only loop, compact: ``` STEP 0 Discover GET /v1/x402/pool/pricing (no auth) STEP 0b Check stock GET /v1/gateway/pool/stock (no auth) STEP 1 Get quote GET /v1/x402/pool?tier=mbl&country=us&traffic=1 -> 402 catalog STEP 2 Pay on-chain send USDC to the 402's payTo (Base ~2s / Solana ~400ms) STEP 3 Redeem same request + Payment-Signature: -> credentials + x402s_ token STEP 4 Use it one credential, every country in the tier - retarget by editing the DSL STEP 5 Monitor GET /v1/x402/manage/pool/credit + /usage STEP 6 Top up new USDC tx -> POST /v1/x402/manage/pool/topup (replay-guarded) Recovery: /manage/pool/regenerate (new secret) - /manage/pool/connection (re-emit) ``` Buying 0.5 GB ($2.00) of US-targeted production mobile access with USDC on Solana: ```bash BASE=https://api.proxies.sx # 1. Discover the price and the recipient curl -s $BASE/v1/x402/pool/pricing # -> mbl $4/GB, Solana recipient 6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv # 2. Confirm US stock exists (counts only) curl -s $BASE/v1/gateway/pool/stock # 3. Get the exact quote (402 = catalog). 0.5 GB -> maxAmountRequired "2000000" (micro-USDC) curl -s "$BASE/v1/x402/pool?tier=mbl&country=us&traffic=0.5&sid=demo_agent_01&rot=sticky" # 4. Pay $2.00 USDC on Solana spl-token transfer EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v 2 \ 6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv \ --fund-recipient --allow-unfunded-recipient # -> Signature: 5KtP...xyz # 5. Retry with the signature -> credentials curl -s "$BASE/v1/x402/pool?tier=mbl&country=us&traffic=0.5&sid=demo_agent_01&rot=sticky" \ -H "Payment-Signature: 5KtP...xyz" # -> Save: proxy.password (pak_...), sessionToken (x402s_...), payment.txHash # 6. Use it - US mobile exit through a production modem curl -x "http://psx_x402pool-mbl-us-sid-demo_agent_01-rot-sticky:pak_YOUR_KEY@gw.proxies.sx:7000" \ https://api.ipify.org # 7. Retarget the UK with the SAME credential - no repurchase # (pick any country stockUrl reports live mbl stock for - as of last edit: us, gb, pl, fr, nl, ge) curl -x "http://psx_x402pool-mbl-gb-sid-demo_agent_01-rot-sticky:pak_YOUR_KEY@gw.proxies.sx:7000" \ https://api.ipify.org # 8. Watch the meter curl -s $BASE/v1/x402/manage/pool/credit -H "X-Session-Token: x402s_YOUR_TOKEN" # -> { "allocatedGB": 0.5, "usedGB": 0.0312, "remainingGB": 0.4688, "enabled": true } # 9. Running low? Top up 1 GB ($4.00) - new payment, new tx hash spl-token transfer EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v 4 \ 6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv curl -s -X POST $BASE/v1/x402/manage/pool/topup \ -H "X-Session-Token: x402s_YOUR_TOKEN" \ -H "Payment-Signature: NEW_SIGNATURE" \ -H "Content-Type: application/json" \ -d '{"addTrafficGB": 1}' # -> { "allocatedGB": 1.5, ... } - and a cap-suspended key is re-enabled ``` Minimal programmatic loop (assumes a `pay_usdc(requirements) -> tx_hash` wallet helper): ```python import requests API = "https://api.proxies.sx" PARAMS = {"tier": "mbl", "country": "us", "traffic": 1} # 1. quote (402 expected) q = requests.get(f"{API}/v1/x402/pool", params=PARAMS) assert q.status_code == 402 req = q.json() # accepts[]: amount, payTo, asset, network tx = pay_usdc(req) # your wallet - Base or Solana # 2. redeem (idempotent - safe to retry with the same tx) r = requests.get(f"{API}/v1/x402/pool", params=PARAMS, headers={"Payment-Signature": tx}) r.raise_for_status() conn = r.json() proxy = conn["proxy"]["http"] # ready-to-use proxy URL token = conn["sessionToken"] # x402s_... # 3. use ip = requests.get("https://httpbin.org/ip", proxies={"http": proxy, "https": proxy}, timeout=30).json() # 4. monitor + 5. top up when low credit = requests.get(f"{API}/v1/x402/manage/pool/credit", headers={"X-Session-Token": token}).json() if credit["remainingGB"] < 0.2: tx2 = pay_usdc_amount(4.00, req) # +1 GB at $4/GB requests.post(f"{API}/v1/x402/manage/pool/topup", headers={"X-Session-Token": token, "Payment-Signature": tx2}, json={"addTrafficGB": 1}) ``` --- ## MCP Tools (`pool_*`) The `@proxies-sx/mcp-server` npm package exposes **16 `pool_*` tools** (plus a separate x402 wallet-side tool group covering the optional wallet flow above). It runs on the standard path - your account API key. Add it to Claude Code / any MCP client: ```json { "mcpServers": { "proxies-sx": { "command": "npx", "args": ["-y", "@proxies-sx/mcp-server"], "env": { "PROXIES_API_KEY": "psx_your_key" } } } } ``` Auth: `PROXIES_API_KEY=psx_...` (API-key mode - the server sends `X-API-Key` on every call; scopes as noted). Optional: `PROXIES_API_URL` (default `https://api.proxies.sx` - do NOT add a `/v1` suffix; endpoint paths already include it), `AGENT_WALLET_KEY` (x402 wallet mode). Key-management tools additionally require a reseller-role key. | Tool | Purpose | |---|---| | `pool_get_stock` | Live availability - endpoint counts per country (no auth) | | `pool_build_proxy_url` | Build a ready proxy URL via the username DSL - pure local, no network call | | `pool_list_sessions` | List your live gateway sessions (traffic, exit IP, country) | | `pool_close_session` | Close one live session by sessionKey | | `pool_get_my_credentials` | Your proxyUsername + HTTP/SOCKS5 connect strings | | `pool_get_my_stats` | Your usage + aggregated pool health | | `pool_set_proxy_password` | Set/update the separate proxy auth password (min 6 chars) | | `pool_mint_key` | Mint a customer pak_ key (label, cap, expiry, qualityTier) - reseller | | `pool_list_keys` | List your pak_ keys (masked) - reseller | | `pool_update_key` | Update key label/enabled/cap/expiry/qualityTier - reseller | | `pool_topup_key` | Atomically add cap GB and/or extend expiry - reseller | | `pool_regenerate_key` | Rotate a key's pak_ secret (old dies immediately) - reseller | | `pool_reveal_key` | Reveal the full pak_ secret (audit-logged) - reseller | | `pool_delete_key` | Delete a pak_ key - reseller | | `pool_key_usage` | Daily in/out MB series for one key - reseller | | `pool_key_audit` | Forensic audit log for one key, newest first - reseller | --- ## Error Handling ### Purchase + management errors (x402 path - API, JSON bodies) | Status | When | What to do | |--------|------|------------| | 402 | No payment header - this is the catalog, not a failure | Pay, retry with `Payment-Signature` | | 402 | `underpaid: need N USDC micro ... got M` | Send the difference as a NEW tx for the full amount, retry with the new hash | | 402 | Payment verification failed (wrong recipient/asset, unconfirmed, older than 24h, unsupported format) | Fix the payment; only direct on-chain Base/Solana USDC transfers are accepted | | 400 | Bad params (`traffic must be a number between 0.1 and 1000 GB`, unknown/disabled tier, bad topup amounts) | Fix the request. Purchasable tiers: `mbl` and `peer`; `peer_mobile` is disabled and returns 400 | | 400 | `invalid or expired session token` / `this session is not a pool-access session` | Use the `x402s_*` token from a POOL purchase | | 409 | `transaction already redeemed for a dedicated port` | One tx = one product. Send a new payment | | 409 | `topup payment already redeemed (replay) - no GB added` | Each tx hash works once. Send a new payment | | 409 | `provisioning race - please retry with the same payment` | Retry the identical call - it re-emits your credentials | | 429 | Throttled: buy 10/min, topup 5/min, regenerate 3/hour | Back off and retry | | 503 | `pool product not configured` | Product is disabled server-side. Try later or file a ticket | ### Connection-time errors (gateway, `CODE: message (req: )` bodies - ALL auth paths) Always log the `req:` uuid - support needs it. | Code | Status | Meaning | Agent reaction | |------|--------|---------|------------| | `E_AUTH_REQUIRED` | 407 | No Proxy-Authorization header | Most HTTP clients need the credentials inside the proxy URL, not as separate headers. Fix the client config - do not retry blind | | `E_BALANCE_EXHAUSTED` | 407 | Password valid, no traffic left on the account - add GB; nothing else to fix | | `E_AUTH_INVALID` | 407 | Credential rejected - the failMsg carries the backend reason (insufficient traffic / key disabled / not found) | Parse the reason: "insufficient traffic" -> deposit more GB (standard path) or top up (x402); "disabled" -> stop and alert; otherwise re-check the credential. Do NOT hammer retries - failures feed the auth rate limiter | | `E_CAP_EXCEEDED` | 407 | This `pak_*` key hit its GB cap (distinct machine code so you can branch) | x402 path: `POST /v1/x402/manage/pool/topup`; reseller pak: `POST /v1/reseller/pool-keys/:keyId/topup` or raise the cap - then retry | | `E_USERNAME_PARSE` | 400 | Username missing or over 256 chars. The parser self-heals bad optional tokens (sanitizes + defaults) rather than rejecting, so this only fires on a missing/oversized username, not on a malformed `-sid-`/`-rot-` value | Fix your DSL builder | | `E_RATE_LIMITED_AUTH` | 429 | Too many failed auth attempts (per-IP: 10/min -> 30s ban, 30/min -> 5min; per-account: 25/min -> 30s, 60/min -> 5min) | STOP retrying with the same bad credentials; wait out the ban window and fix the credential first. Bans clear instantly on one successful auth | | `E_RATE_LIMITED_CONN` | 429 | Over 500 concurrent connections per account (default) | Lower parallelism / pool connections with a hard ceiling < 500. Backoff + retry is fine | | `E_NO_STOCK_COUNTRY` | 502 | No online endpoints for that pool/country | failMsg suggests the nearest alternative; re-fetch stockUrl, switch country or pool (`peer-de` <-> `mbl-gb` style), retry. Do not tight-loop the same pool/country | | `E_STOCK_DEGRADED` | 502 | Selected endpoint dropped mid-request | Transient - retry once immediately (the selector picks another endpoint); if it repeats, treat like `E_NO_STOCK_COUNTRY` | | `E_SESSION_LIMIT` | 429 | Over 250 concurrent sessions per account (default; contact support to discuss raises) | Reuse `-sid-` values instead of minting one per request; let idle sessions expire (default ttl 3600s) | | `E_SSRF_BLOCKED` | 403 | Target is private/localhost/cloud-metadata | Never retry - your agent tried to reach an internal address; treat as a target bug | | `E_INTERNAL` | 503 | Unexpected | Retry with backoff (1s, 5s, 30s); if persistent, file a ticket with the req id | Design around the per-account limits: **500 concurrent connections, 250 concurrent sessions** (not the older 100/50 figures floating in stale docs). Authoritative list: [docs-manifest.json](https://agents.proxies.sx/docs-manifest.json) under `pool_gateway.error_codes`. **Support:** maya@proxies.sx or https://t.me/proxies_sx - quote the `req` id from the error body. ### Recovery matrix **Standard path (account):** nothing is ever unrecoverable - `GET /v1/gateway/credentials` re-emits your username + connect strings, `GET /v1/account/proxy-password` returns the current proxy password, and `PATCH /v1/account/proxy-password` mints a new one at any time. Lost the API key itself? Sign in with your JWT and mint a new one at `POST /v1/api-keys` (max 5 active). **x402 path (wallet-only):** | You still have | Recovery | |----------------|----------| | `sessionToken` | `GET /v1/x402/manage/pool/connection` re-emits everything | | Only the purchase `txHash` | Retry `GET /v1/x402/pool` with `Payment-Signature: ` - re-emits the same credentials + session token | | Leaked password | `POST /v1/x402/manage/pool/regenerate` - new secret, same credit | | Nothing | Unrecoverable. Always persist `sessionToken` + `txHash` at purchase time | --- ## Caveats (Read Before You Build) These are the contract, whichever auth path you use: 1. **Sticky pins the MODEM, not the IP.** Carrier NAT may re-issue exit IPs even on a pinned modem. For a held IP use a residential `peer` exit or the dedicated port product. 2. **`sticky`/`auto*` require a `-sid-`** to persist across connections (1-64 chars `[a-z0-9_]` at the gateway; use 8-64 to also satisfy the x402 purchase endpoint). Without one, every connection starts a fresh synthetic session. 3. **No token value may contain `-`** - the username is lowercased and split on `-`. 4. **The account/login password does NOT work on the gateway.** Set a separate proxy password (`PATCH /v1/account/proxy-password`) - there is NO fallback. 5. **Minted `safe`-tier pak keys are quality-locked:** `peer` routes in the username are silently served from modems (safe rewrite) - by design, never a bug. Account credentials and `standard` paks route their pool token as written. 6. **HTTP `:7000` and SOCKS5 `:7001` both work for every credential shape** - account, reseller-pak, and x402-minted alike, metered identically. 7. **Metering is live.** Account credentials draw from deposited GB and are rejected at zero; pak keys cap-suspend within ~5-35s of hitting the GB cap. No refunds of unused GB. Deposits/top-ups re-enable. 8. **Per-GB metered only.** There is no flat-rate or unlimited plan. Duration is free; traffic is the only thing you pay for. --- ## Copy-Paste Client Examples `YOUR_PASSWORD` below is your account **proxy password** (standard path) or a `pak_*` key (reseller/x402 paths). Same DSL, same gateway. ### curl - HTTP proxy (:7000, any credential) ```bash # Stable US mobile modem, sticky session curl -x "http://psx_YOUR_ACCOUNT-mbl-us-sid-job42lane1-rot-sticky:YOUR_PASSWORD@gw.proxies.sx:7000" \ https://httpbin.org/ip # Flagship peer network, Germany (no mbl stock in DE - 'ge' is Georgia!) curl -x "http://psx_YOUR_ACCOUNT-peer-de-sid-job42lane1:YOUR_PASSWORD@gw.proxies.sx:7000" \ https://httpbin.org/ip ``` ### curl - SOCKS5 (:7001, works for account, reseller-pak, and x402-minted credentials) ```bash curl -x "socks5://psx_YOUR_ACCOUNT-mbl-gb-sid-job42lane1-rot-sticky:YOUR_PASSWORD@gw.proxies.sx:7001" \ https://httpbin.org/ip ``` ### Python (requests) ```python import requests USER = "psx_YOUR_ACCOUNT-mbl-us-sid-job42lane1-rot-sticky" # sid REQUIRED for stickiness PASS = "YOUR_PROXY_PASSWORD" # or pak_YOUR_KEY (reseller/x402) proxy = f"http://{USER}:{PASS}@gw.proxies.sx:7000" proxies = {"http": proxy, "https": proxy} r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30) print(r.json()) # Retry pattern for peer/best pools (tunnels can drop - expect failover): for attempt in range(3): try: r = requests.get("https://example.com", proxies=proxies, timeout=30) break except requests.exceptions.ProxyError: # E_STOCK_DEGRADED / dropped tunnel -> gateway picks another endpoint on retry if attempt == 2: raise ``` ### Node.js (undici) ```js const { ProxyAgent, fetch } = require("undici"); const USER = "psx_YOUR_ACCOUNT-mbl-us-sid-job42lane1-rot-sticky"; const PASS = "YOUR_PROXY_PASSWORD"; // or pak_YOUR_KEY (reseller/x402) const dispatcher = new ProxyAgent(`http://${USER}:${PASS}@gw.proxies.sx:7000`); const res = await fetch("https://httpbin.org/ip", { dispatcher }); console.log(await res.json()); ``` --- ## Pool Access vs Dedicated Port - Which to Buy | | Pool Gateway Access (this skill) | Dedicated Port | |---|---|---| | Buy it via | API key + deposited GB (standard) or `GET/POST /v1/x402/pool` (USDC, optional) | `POST /v1/ports` with your API key (standard) or `GET/POST /v1/x402/proxy` (USDC, optional) | | What you get | One credential, every country in the tier, shared modem pool | One dedicated modem port in one country | | Country switching | Edit the username token - instant, free | New purchase per country | | IP stability | Sticky pins a modem; carrier NAT may still re-issue the IP | Same carrier-NAT caveat, but the modem is exclusively yours | | IP rotation | `rot` modes (modem switching) | Explicit `/rotate/:token` (carrier IP reset); auto-rotation scheduling on the account path | | Protocols | HTTP :7000 + SOCKS5 :7001 (all credential shapes) | HTTP + SOCKS5 | | Price | $4/GB | $4/GB | On the x402 path, one tx hash buys exactly one of them - never both. On the standard path both draw from the same account: deposited GB meters the pool; dedicated ports are created with `POST /v1/ports` (see [/marketplace/skill.md](https://agents.proxies.sx/marketplace/skill.md)). --- ## Links | Resource | URL | |----------|-----| | This skill file | https://agents.proxies.sx/pool/skill.md | | Rotation cookbook | https://agents.proxies.sx/pool/rotation-cookbook.md | | Customer portal (sign-up, keys, billing) | https://client.proxies.sx | | Live pricing (standard path) | https://api.proxies.sx/v1/billing/pricing | | Live pricing (x402 path) | https://api.proxies.sx/v1/x402/pool/pricing | | Live stock (counts only) | https://api.proxies.sx/v1/gateway/pool/stock | | Master skill (full infra) | https://agents.proxies.sx/skill.md | | Dedicated port skill | https://agents.proxies.sx/marketplace/skill.md | | Earn as a peer | https://agents.proxies.sx/peer/skill.md | | x402 discovery | https://agents.proxies.sx/.well-known/x402.json | | docs-manifest.json (truth) | https://agents.proxies.sx/docs-manifest.json | | llms.txt | https://agents.proxies.sx/llms.txt | --- ## Changelog - **2026-07-25**: SOCKS5 now works for x402-minted credentials too (`gw.proxies.sx:7001`), metered identically to HTTP `:7000` - the gateway now plumbs `pakKeyId` through the SOCKS5 accountant the same way it already did for HTTP. Every "HTTP only for x402" / "SOCKS5 :7001 rejects this credential" note in this file, `llms.txt`, and `index.html` was stale and has been corrected. Also brought the MCP tool count reference in line with the published npm 2.4.0 (70 api-key + 19 x402 tools, `pool_*` group still 16). - **2026-07-24**: API-FIRST restructure. The account path (API key + deposited GB) is now documented as the STANDARD, most-used way in - new full walkthrough (mint key via `POST /v1/api-keys`, deposit GB via `POST /v1/billing/purchase-traffic`, proxy password via `PATCH /v1/account/proxy-password`, bulk spawn via `POST /v1/gateway/pool/spawn`, monitor via `my-stats`/`my-sessions`/`account/summary`), with `X-API-Key` on every copy-paste example. The Three Ways In reordered (account first, reseller pak second, x402 third). The entire x402 flow is preserved unchanged under "Optional: Pay with USDC (x402, No Account)". Username DSL cheatsheet promoted to a top-level auth-agnostic section. Recovery matrix now covers the account path. Title dropped the "(x402 USDC)" suffix - the pool gateway is one product with two payment paths. - **2026-07-24**: Completion pass. `peer` tier documented as LIVE/purchasable everywhere (removed the stale "only mbl is purchasable" error-table note; pricing example now shows both tiers; peer-credential semantics documented - standard quality, pool token routes as written). Full username DSL cheatsheet added (`iptype`, `isp`, `asn`, `pin`, `strict`, aliases, self-healing parser, the germany->de trap). `E_CAP_EXCEEDED` gateway code added with the correct branch reaction. New sections: The Three Ways In (x402 / account / reseller pak), Choosing a Network (mbl vs peer vs best, with the real `best`->`mbl-gb` incident), The Full Pool Surface (public + account + reseller REST incl. `POST /v1/gateway/pool/spawn`), MCP tools (16 `pool_*` tools + install), Python/Node/SOCKS5 client examples, minimal programmatic agent loop. sid length reconciled (purchase 8-64; parser 1-64). - **2026-06-12**: Initial release. v1 = `mbl` tier only ($4/GB, production modems, HTTP :7000). Buy via `GET/POST /v1/x402/pool` (402 catalog -> pay USDC on Base/Solana -> `Payment-Signature` retry). Management via `X-Session-Token`: credit, connection, usage, regenerate (3/hour), topup (5/min, replay-guarded, re-enables cap-suspended keys). Idempotent purchase retries by tx hash. `peer`/`peer_mobile` tiers gated off pending gateway IP-type enforcement (since lifted for `peer`). --- *Managed by Maya (openclaw bot) | Pool Gateway Access* |