# Quickstart: rent a private 4G/5G modem Last verified: 2026-10-28. Base URL `https://api.proxies.sx/v1`, header `X-API-Key: psx_...` with the `modems:purchase` scope (tick it when creating the key at https://client.proxies.sx/account). Every money step needs the user's approval of the amount. Full contract: https://agents.proxies.sx/modems/skill.md 1. **Read the catalog** (stock and prices are live; never quote a remembered price). ```bash curl -s https://api.proxies.sx/v1/private-modems/catalog -H "X-API-Key: $KEY" \ | jq '.tariffs[] | select(.stock>0) | {tariffId,countryCode,period,priceUsd,stock,openvpn,p0f}' ``` Verify: at least one plan prints. 401 = bad key; `{"enabled":false}` from `GET /v1/private-modems/status` = the product is off. 2. **Quote** = the plan's `priceUsd` (per unit). Show it and get a yes. 3. **Buy** with a fresh `Idempotency-Key` and the price you showed. ```bash curl -s -X POST https://api.proxies.sx/v1/private-modems/orders -H "X-API-Key: $KEY" \ -H "Idempotency-Key: $(uuidgen)" -H 'Content-Type: application/json' \ -d '{"tariffId":"t_...","expectedPriceUsd":12}' # -> 201 {"orderId":"o_...","kind":"buy","status":"pending","priceUsd":12,...} ``` Verify: 201. 409 `price_changed` -> re-read the price, confirm, resend with the new `expectedPriceUsd` and a NEW key. 400 `insufficient_balance` -> nothing charged; top up (https://agents.proxies.sx/quickstart/topup.md) and order again with a NEW key. 403 `scope_missing` -> the key lacks `modems:purchase`. A timeout is retried with the SAME key and body (same order comes back). 4. **Poll** until the modem is active (10-60 s). ```bash curl -s https://api.proxies.sx/v1/private-modems/mine -H "X-API-Key: $KEY" | jq '.openOrders, .modems[] | {id,status,online,expiresAt,credentials}' ``` Verify: `openOrders` is `[]`, the modem has `status:"active"`, `online:true` and `credentials.http` / `credentials.socks5` filled. 5. **Connect** (hosts below are placeholders; use the ones from step 4). ```bash curl -s -x "http://u_...:p_...@modem-host.example:10001" https://api.ipify.org ``` Verify: `x.x.x.x` (equals `currentIp`). SOCKS5: `-x socks5h://...:10002`. OpenVPN: `GET /v1/private-modems//openvpn -o modem.ovpn`. 6. **Rotate** when you need a new IP. ```bash curl -s -X POST https://api.proxies.sx/v1/private-modems//rotate -H "X-API-Key: $KEY" # -> {"rotated":true,"pending":false,"message":"New IP assigned."} ``` Verify: step 5 returns a different IP (wait about a minute if `pending` was true). Public link for scripts, 1/min: `GET https://api.proxies.sx/v1/private-modems/rotate/`. 7. **Renew** before `expiresAt` (ask the user), or switch on auto-renew. ```bash curl -s https://api.proxies.sx/v1/private-modems//renewal-quote -H "X-API-Key: $KEY" # -> options[] with priceUsd per period curl -s -X POST https://api.proxies.sx/v1/private-modems//renew -H "X-API-Key: $KEY" \ -H "Idempotency-Key: $(uuidgen)" -H 'Content-Type: application/json' -d '{"expectedPriceUsd":12,"period":"day"}' curl -s -X PUT https://api.proxies.sx/v1/private-modems//auto-renew -H "X-API-Key: $KEY" \ -H 'Content-Type: application/json' -d '{"enabled":true,"period":"day"}' # -> {"autoRenew":true,"autoRenewPeriod":"day"} ``` Verify: `GET /v1/private-modems/mine` shows the later `expiresAt` (or `autoRenew:true`). 409 `renewal_open` = one is already running; wait and read `mine`.