PRIVATE MODEMS

One whole 4G/5G modem rented to you: unlimited traffic, your own HTTP and SOCKS5 host:port, optional OpenVPN profile and OS fingerprint, rotate the IP whenever you want. Rent it per day, week or month, paid from your account balance, by API or in the dashboard.
1 modem, exclusively yours
Unlimited traffic for the term
HTTP + SOCKS5 + OpenVPN
LIVE

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", ... } ] }
Buy flow | Use it | Renew | Errors | Links

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.

BUY FLOW: CATALOG → QUOTE → BUY → POLL

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.

StepCallVerify
1. CatalogGET /v1/private-modems/catalogtariffs[] with stock > 0; note tariffId, period, priceUsd
2. Quotethe plan's priceUsd (per unit)shown to the user, answered with a yes
3. BuyPOST /v1/private-modems/orders with header Idempotency-Key: <uuid> and body {"tariffId","expectedPriceUsd"}201, status is pending or succeeded
4. PollGET /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.


USE IT: HTTP, SOCKS5, OPENVPN, ROTATE

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" }
NeedCall
Rotate automaticallyPUT /v1/private-modems/:id/rotation-interval {"seconds": 600} (0 = off, else 60 to 86400)
New public rotation linkPOST /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 countryPOST /v1/private-modems/:id/replace (credentials change, paid time carries over)
Everything you rentGET /v1/private-modems/mine or the dashboard

RENEW AND AUTO-RENEW

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)

ERRORS (JSON BODY WITH code AND fix)

HTTPcodeDo this
403scope_missingthe key lacks modems:purchase; a human creates one with that scope
400expected_price_requiredsend expectedPriceUsd from the catalog or renewal quote
409price_changedthe body carries the new priceUsd: confirm with the user, resend with it and a new Idempotency-Key
409no_stockre-read the catalog and pick another plan or region
400insufficient_balancenothing charged, the order is recorded as failed: top up (/quickstart/topup.md), then order again with a new Idempotency-Key
409recent_checkout / recent_renewalthe same thing was bought under 2 minutes ago; if intended, resend with "confirmAgain": true
409renewal_opena renewal is in progress: wait, then read mine

Every code, including the gateway and x402 families: /errors.md.


WhatWhere
Machine contract (this product)/modems/skill.md
Quickstart/quickstart/buy-modem.md
Top up the balance by API/quickstart/topup.md
Dashboardclient.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)
Supportmaya@proxies.sx · t.me/proxies_sx