This is the product for a dedicated, port, exclusive-device, p0f, OpenVPN or unlimited request. The legacy per-port pool at /marketplace/proxy/ is nearly full; start here. Metered GB for many countries from one credential is the other product: Pool Gateway.
First request (any API key, stock and prices are live):
curl -s https://api.proxies.sx/v1/private-modems/catalog -H "X-API-Key: psx_YOUR_KEY"
# -> { "maxCartModems": 10, "tariffs": [ { "tariffId": "t_...", "period": "day", "countryCode": "DE",
# "countryName": "Germany", "carrierName": "...", "stock": 3, "priceUsd": 12, "openvpn": "all", "p0f": "some", ... } ] }
Canonical machine contract: /modems/skill.md; quickstart: /quickstart/buy-modem.md. If this page disagrees with the skill file, the skill file wins; if the skill file disagrees with the live API, the live API wins. Last verified: 2026-10-28.
Prices are never printed in these docs: a plan's priceUsd comes from the catalog at the moment you buy, and the server refuses a purchase whose expectedPriceUsd no longer matches. Buying and renewing need an API key with the modems:purchase scope (tick it when you create the key at client.proxies.sx/account); every other call works with any key. Every spend needs the user's approval of the amount.
| Step | Call | Verify |
|---|---|---|
| 1. Catalog | GET /v1/private-modems/catalog | tariffs[] with stock > 0; note tariffId, period, priceUsd |
| 2. Quote | the plan's priceUsd (per unit) | shown to the user, answered with a yes |
| 3. Buy | POST /v1/private-modems/orders with header Idempotency-Key: <uuid> and body {"tariffId","expectedPriceUsd"} | 201, status is pending or succeeded |
| 4. Poll | GET /v1/private-modems/mine every 5 s (setup takes 10-60 s) | openOrders empty; the modem has status: "active", online: true and credentials |
# 3. Buy (the same Idempotency-Key + same body returns the same order, so a timeout is retried as-is)
curl -s -X POST https://api.proxies.sx/v1/private-modems/orders \
-H "X-API-Key: psx_YOUR_KEY" -H "Idempotency-Key: $(uuidgen)" -H 'Content-Type: application/json' \
-d '{"tariffId":"t_...","expectedPriceUsd":12}'
# -> 201 { "orderId": "o_...", "kind": "buy", "status": "pending", "priceUsd": 12, "countryName": "Germany", "period": "day", ... }
# 4. Poll
curl -s https://api.proxies.sx/v1/private-modems/mine -H "X-API-Key: psx_YOUR_KEY"
# -> { "openOrders": [], "recentFailed": [], "modems": [ { "id": "m_...", "status": "active", "online": true,
# "expiresAt": "2026-10-29T10:00:00.000Z", "currentIp": "x.x.x.x", "rotationToken": "rt_...",
# "credentials": { "http": { "host": "modem-host.example", "port": 10001, "username": "u_...", "password": "p_..." },
# "socks5": { "host": "modem-host.example", "port": 10002, "username": "u_...", "password": "p_..." } },
# "capabilities": { "rotate": true, "openvpn": true, "p0f": false, "replace": true }, "autoRenew": false } ] }
Several modems in one checkout: body {"items":[{"tariffId","quantity","regionId?","p0f?","expectedPriceUsd"}],"confirmAgain?"}, debited once, at most maxCartModems. A failed order shows up in recentFailed with refunded: true. currentIp is your own modem's exit; keep it private.
curl -s -x "http://u_...:p_...@modem-host.example:10001" https://api.ipify.org # HTTP -> x.x.x.x
curl -s -x "socks5h://u_...:p_...@modem-host.example:10002" https://api.ipify.org # SOCKS5 -> x.x.x.x
curl -s https://api.proxies.sx/v1/private-modems/m_.../openvpn -H "X-API-Key: psx_YOUR_KEY" -o modem.ovpn # OpenVPN profile
# Rotate now (API)
curl -s -X POST https://api.proxies.sx/v1/private-modems/m_.../rotate -H "X-API-Key: psx_YOUR_KEY"
# -> { "rotated": true, "pending": false, "message": "New IP assigned." }
# { "rotated": false, "pending": true, "message": "Rotation requested. The new IP shows up in about a minute." }
# Rotate from any script, no auth, one call per modem per 60 s (the token is in `mine`)
curl -s https://api.proxies.sx/v1/private-modems/rotate/rt_...
# -> { "rotated": true, "pending": false, "ip": "x.x.x.x" }
| Need | Call |
|---|---|
| Rotate automatically | PUT /v1/private-modems/:id/rotation-interval {"seconds": 600} (0 = off, else 60 to 86400) |
| New public rotation link | POST /v1/private-modems/:id/rotation-token (the old link stops working) |
| OS fingerprint (p0f) | GET /v1/private-modems/:id/p0f-options, then PUT /v1/private-modems/:id/os {"os": "..."} ("" = off; one change per 5 minutes) |
| Swap to another modem, same country | POST /v1/private-modems/:id/replace (credentials change, paid time carries over) |
| Everything you rent | GET /v1/private-modems/mine or the dashboard |
curl -s https://api.proxies.sx/v1/private-modems/m_.../renewal-quote -H "X-API-Key: psx_YOUR_KEY"
# -> { "defaultPeriod": "day", "priceUsd": 12, "options": [ { "period": "day", "days": 1, "priceUsd": 12, "available": true, "extendsTo": "..." }, ... ] }
curl -s -X POST https://api.proxies.sx/v1/private-modems/m_.../renew \
-H "X-API-Key: psx_YOUR_KEY" -H "Idempotency-Key: $(uuidgen)" -H 'Content-Type: application/json' \
-d '{"expectedPriceUsd":12,"period":"day"}'
# -> 201 { "orderId": "o_...", "kind": "renew", "status": "pending", ... } then `mine` shows the later expiresAt
curl -s -X PUT https://api.proxies.sx/v1/private-modems/m_.../auto-renew \
-H "X-API-Key: psx_YOUR_KEY" -H 'Content-Type: application/json' -d '{"enabled":true,"period":"week"}'
# -> { "autoRenew": true, "autoRenewPeriod": "week" } (charges the balance before the term ends; `autoRenewIssue` in `mine` says when it could not)
code AND fix)| HTTP | code | Do this |
|---|---|---|
| 403 | scope_missing | the key lacks modems:purchase; a human creates one with that scope |
| 400 | expected_price_required | send expectedPriceUsd from the catalog or renewal quote |
| 409 | price_changed | the body carries the new priceUsd: confirm with the user, resend with it and a new Idempotency-Key |
| 409 | no_stock | re-read the catalog and pick another plan or region |
| 400 | insufficient_balance | nothing charged, the order is recorded as failed: top up (/quickstart/topup.md), then order again with a new Idempotency-Key |
| 409 | recent_checkout / recent_renewal | the same thing was bought under 2 minutes ago; if intended, resend with "confirmAgain": true |
| 409 | renewal_open | a renewal is in progress: wait, then read mine |
Every code, including the gateway and x402 families: /errors.md.
| What | Where |
|---|---|
| Machine contract (this product) | /modems/skill.md |
| Quickstart | /quickstart/buy-modem.md |
| Top up the balance by API | /quickstart/topup.md |
| Dashboard | client.proxies.sx/private-modems |
| Metered GB instead (one credential, every country) | /pool/ |
| Legacy dedicated port pool (nearly full) | /marketplace/proxy/ |
| Pricing table and payment routes | /pricing.json (modem prices only live, in the catalog) |
| Support | maya@proxies.sx · t.me/proxies_sx |