Developers

Reseller API

Sell ProxyStream 4G and 5G mobile proxies under your own brand. List servers, buy proxies from your balance, and manage credentials, whitelist IPs, locations and IP rotation over a small REST API.

Base URLhttps://proxystream.net/api/reseller/v1

Quickstart

1. Find a server and its prices. Store your key in PROXYSTREAM_API_KEY.

Shell
curl https://proxystream.net/api/reseller/v1/servers \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"

2. Buy a proxy on it. The response contains everything needed to connect.

Shell
curl -X POST https://proxystream.net/api/reseller/v1/proxies \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"server_id":12,"duration":"1w"}'

3. Use it.

Shell
curl -x http://a7k2m9x:q4w8e1r@168.231.79.20:8010 https://api.ipify.org

Authentication

Send your API key as a bearer token on every request:

Header
Authorization: Bearer psr_...

Request reseller access from your API page. Once approved, create one API key there. If you lose it or need a replacement, contact us on Telegram or at support@proxystream.net. A key belongs to one ProxyStream account: purchases are paid from that account's balance, which you top up on the deposit page, and the account owns every proxy you buy.

Keep the key on your server and never ship it to browsers or apps. If it leaks, contact support immediately so we can revoke and replace it.

Conventions

  • Requests and responses are JSON. Send Content-Type: application/json with a body.
  • Amounts are USD numbers with two decimals. Times are ISO 8601 in UTC.
  • Rate limit: 120 requests per minute per key. Beyond that you get rate_limited with a Retry-After header.
  • Lists are paginated with a cursor: pass next_cursor as cursor until it is null.
  • Versioning: /v1 only gains new optional fields and new endpoints, so ignore fields you don't know. Breaking changes ship as /v2, and /v1 keeps running for at least 6 months after that is announced.

Durations

CodeLength
4h4 hours
1d1 day
3d3 days
1w7 days
1mo1 calendar month

Your price for each duration depends on the server's plan, and is in the server list.

Plans

Every server is on one plan, shown as plan on the server. A proxy keeps the plan of the server you bought it on, and can only move to servers on the same plan.

Featurestandardadvanced
PortsOne port for both HTTP and SOCKS5, so http_port equals socks_port.A dedicated HTTP port and SOCKS5 port for each proxy.
IP rotationOn the server's schedule (rotation_minutes).On request, through the proxy's rotation_url.

Endpoints

All paths are relative to https://proxystream.net/api/reseller/v1. Any endpoint can also return unauthorized, rate_limited or internal_error.

List servers

GET/servers

Servers that are online and have free capacity right now, best quality first, with your price for each duration. Prices depend on the server's plan. A server that fills up drops out of this list until a slot frees up.

Request
curl https://proxystream.net/api/reseller/v1/servers \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"
Response · 200 OK
{
  "data": [
    {
      "id": 12,
      "country": "US",
      "region": "Texas",
      "isp": "T-Mobile",
      "type": "Mobile 5G",
      "plan": "standard",
      "rotation_minutes": 15,
      "prices": [
        {
          "duration": "4h",
          "price": 0.6
        },
        {
          "duration": "1d",
          "price": 1
        },
        {
          "duration": "3d",
          "price": 2.5
        },
        {
          "duration": "1w",
          "price": 5
        },
        {
          "duration": "1mo",
          "price": 16
        }
      ]
    }
  ]
}

Get balance

GET/balance

The balance of your account. Every purchase is paid from it.

Request
curl https://proxystream.net/api/reseller/v1/balance \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"
Response · 200 OK
{
  "balance": 42.5,
  "currency": "USD"
}

Buy a proxy

POST/proxies

Charges your balance the price listed for the server in GET /servers and returns the new proxy, ready to use. The proxy gets the server's plan. Username and password are generated for you. You can change both afterwards.

Buying is not idempotent. If a request times out, check GET /proxies?status=active before retrying, or you may buy twice.

Request body

FieldTypeDescription
server_id*integerA server id from GET /servers.
duration*stringOne of the duration codes.
Request
curl -X POST https://proxystream.net/api/reseller/v1/proxies \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"server_id":12,"duration":"1w"}'
Response · 201 Created
{
  "id": 90412,
  "status": "active",
  "host": "168.231.79.20",
  "http_port": 8010,
  "socks_port": 8010,
  "username": "a7k2m9x",
  "password": "q4w8e1r",
  "whitelist_ip": null,
  "rotation_url": null,
  "server": {
    "id": 12,
    "country": "US",
    "region": "Texas",
    "isp": "T-Mobile",
    "type": "Mobile 5G",
    "plan": "standard",
    "rotation_minutes": 15
  },
  "created_at": "2026-09-27T10:00:00.000Z",
  "expires_at": "2026-10-04T10:00:00.000Z"
}

Errors: invalid_request, insufficient_balance, server_unavailable

List proxies

GET/proxies

All proxies on your account, newest first, one page at a time. Keep requesting with cursor set to next_cursor until next_cursor is null.

Query parameters

FieldTypeDescription
statusstringactive or expired. Omit for both.
limitintegerPage size, 1 to 100. Default 50.
cursorstringnext_cursor from the previous page, unchanged.
Request
curl https://proxystream.net/api/reseller/v1/proxies?status=active&limit=50 \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"
Response · 200 OK
{
  "data": [
    {
      "id": 90412,
      "status": "active",
      "host": "168.231.79.20",
      "http_port": 8010,
      "socks_port": 8010,
      "username": "a7k2m9x",
      "password": "q4w8e1r",
      "whitelist_ip": null,
      "rotation_url": null,
      "server": {
        "id": 12,
        "country": "US",
        "region": "Texas",
        "isp": "T-Mobile",
        "type": "Mobile 5G",
        "plan": "standard",
        "rotation_minutes": 15
      },
      "created_at": "2026-09-27T10:00:00.000Z",
      "expires_at": "2026-10-04T10:00:00.000Z"
    }
  ],
  "next_cursor": "OTA0MTI"
}

Errors: invalid_request

Get a proxy

GET/proxies/{id}

One proxy with its connection details.

Request
curl https://proxystream.net/api/reseller/v1/proxies/90413 \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"
Response · 200 OK
{
  "id": 90413,
  "status": "active",
  "host": "168.231.79.20",
  "http_port": 20000,
  "socks_port": 20001,
  "username": "a7k2m9x",
  "password": "q4w8e1r",
  "whitelist_ip": null,
  "rotation_url": "https://proxystream.net/api/rotate/Xk3v9QpL2mN8rT5wY1zA4bC7dE0fG6hJ9kM2nP5qR8s",
  "server": {
    "id": 31,
    "country": "US",
    "region": "Texas",
    "isp": "T-Mobile",
    "type": "Mobile 5G",
    "plan": "advanced",
    "rotation_minutes": null
  },
  "created_at": "2026-09-27T10:00:00.000Z",
  "expires_at": "2026-10-04T10:00:00.000Z"
}

Errors: not_found

Set whitelist IP

PUT/proxies/{id}/whitelist-ip

Lets one IPv4 address use the proxy without a username and password. Username and password keep working either way. Send null to clear it. Takes effect within about a minute.

Request body

FieldTypeDescription
whitelist_ip*string | nullAn IPv4 address, or null.
Request
curl -X PUT https://proxystream.net/api/reseller/v1/proxies/90412/whitelist-ip \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"whitelist_ip":"203.0.113.7"}'
Response · 200 OK
{
  "id": 90412,
  "status": "active",
  "host": "168.231.79.20",
  "http_port": 8010,
  "socks_port": 8010,
  "username": "a7k2m9x",
  "password": "q4w8e1r",
  "whitelist_ip": "203.0.113.7",
  "rotation_url": null,
  "server": {
    "id": 12,
    "country": "US",
    "region": "Texas",
    "isp": "T-Mobile",
    "type": "Mobile 5G",
    "plan": "standard",
    "rotation_minutes": 15
  },
  "created_at": "2026-09-27T10:00:00.000Z",
  "expires_at": "2026-10-04T10:00:00.000Z"
}

Errors: invalid_request, not_found, proxy_expired

Change password

PUT/proxies/{id}/password

Sets a new proxy password. The username stays the same. Takes effect within about a minute.

Request body

FieldTypeDescription
password*string6 to 64 characters: letters, digits, dot, underscore or hyphen.
Request
curl -X PUT https://proxystream.net/api/reseller/v1/proxies/90412/password \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"password":"k3y-Rotated_2"}'
Response · 200 OK
{
  "id": 90412,
  "status": "active",
  "host": "168.231.79.20",
  "http_port": 8010,
  "socks_port": 8010,
  "username": "a7k2m9x",
  "password": "k3y-Rotated_2",
  "whitelist_ip": null,
  "rotation_url": null,
  "server": {
    "id": 12,
    "country": "US",
    "region": "Texas",
    "isp": "T-Mobile",
    "type": "Mobile 5G",
    "plan": "standard",
    "rotation_minutes": 15
  },
  "created_at": "2026-09-27T10:00:00.000Z",
  "expires_at": "2026-10-04T10:00:00.000Z"
}

Errors: invalid_request, not_found, proxy_expired

Change username

PUT/proxies/{id}/username

Sets a new proxy username. The password stays the same. Usernames are unique across all active proxies, so pick something specific to your customer. Takes effect within about a minute.

Request body

FieldTypeDescription
username*string4 to 32 characters: letters and digits only.
Request
curl -X PUT https://proxystream.net/api/reseller/v1/proxies/90412/username \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username":"acme0042"}'
Response · 200 OK
{
  "id": 90412,
  "status": "active",
  "host": "168.231.79.20",
  "http_port": 8010,
  "socks_port": 8010,
  "username": "acme0042",
  "password": "q4w8e1r",
  "whitelist_ip": null,
  "rotation_url": null,
  "server": {
    "id": 12,
    "country": "US",
    "region": "Texas",
    "isp": "T-Mobile",
    "type": "Mobile 5G",
    "plan": "standard",
    "rotation_minutes": 15
  },
  "created_at": "2026-09-27T10:00:00.000Z",
  "expires_at": "2026-10-04T10:00:00.000Z"
}

Errors: invalid_request, not_found, proxy_expired, username_taken

Change server

PUT/proxies/{id}/server

Moves the proxy to another server on the same plan, for example another carrier or region. Free of charge, and the expiry date does not change. The host and ports can change, so use the proxy in the response.

Request body

FieldTypeDescription
server_id*integerA server id from GET /servers with the same plan as the proxy.
Request
curl -X PUT https://proxystream.net/api/reseller/v1/proxies/90412/server \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"server_id":17}'
Response · 200 OK
{
  "id": 90412,
  "status": "active",
  "host": "168.231.79.20",
  "http_port": 8017,
  "socks_port": 8017,
  "username": "a7k2m9x",
  "password": "q4w8e1r",
  "whitelist_ip": null,
  "rotation_url": null,
  "server": {
    "id": 17,
    "country": "US",
    "region": "New York",
    "isp": "Verizon",
    "type": "Mobile 5G",
    "plan": "standard",
    "rotation_minutes": 15
  },
  "created_at": "2026-09-27T10:00:00.000Z",
  "expires_at": "2026-10-04T10:00:00.000Z"
}

Errors: invalid_request, not_found, proxy_expired, server_unavailable

Get usage

GET/proxies/{id}/usage

Traffic the proxy has used today (UTC day), in bytes. Usage is collected periodically, so it can trail live traffic by a few minutes. Works for expired proxies too.

Request
curl https://proxystream.net/api/reseller/v1/proxies/90412/usage \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"
Response · 200 OK
{
  "date": "2026-10-12",
  "bytes_used": 52428800
}

Errors: not_found

Check health

GET/proxies/{id}/health

Checks the mobile device behind the proxy and returns its current public IP. Can take up to 15 seconds. A check made in the last minute is returned as-is, with latency_ms null. When status is offline, exit_ip is null.

Request
curl https://proxystream.net/api/reseller/v1/proxies/90412/health \
  -H "Authorization: Bearer $PROXYSTREAM_API_KEY"
Response · 200 OK
{
  "status": "online",
  "exit_ip": "172.58.12.34",
  "latency_ms": 840,
  "checked_at": "2026-10-12T09:30:00.000Z"
}

Errors: not_found, proxy_expired

Rotate IP (Advanced)

GET{rotation_url}

Gets a new exit IP for an Advanced proxy. Call the proxy's rotation_url with GET or POST. The link is the credential: it needs no API key, so you can give it to your customer. Each proxy can rotate once every 3 minutes. The new IP is ready a few seconds after the response.

Anyone with the link can rotate the proxy's IP. Treat it like a password. It stays the same for the life of the proxy.

Request
curl -X POST https://proxystream.net/api/rotate/Xk3v9QpL2mN8rT5wY1zA4bC7dE0fG6hJ9kM2nP5qR8s
Response · 200 OK
{
  "status": "success",
  "message": "IP rotation started. Your new IP will be ready in a few seconds."
}

Other responses

Same JSON shape with "status": "error" and a readable message.

StatusMeaning
403The proxy is no longer on the Advanced plan.
404The link is invalid or the proxy has expired.
429Rotated less than 3 minutes ago. Wait retry_after seconds (also in Retry-After).
502, 504The carrier did not confirm the rotation. Wait a few minutes, then try again.
503Rotation is temporarily unavailable on this server.

Objects

Proxy

Returned by every proxy endpoint, always in this shape.

FieldTypeDescription
idintegerProxy id.
statusstringactive, or expired once expires_at has passed.
hoststringProxy host to connect to.
http_portinteger | nullHTTP/HTTPS proxy port. On Standard, the same port as socks_port.
socks_portinteger | nullSOCKS5 proxy port. On Standard, the same port as http_port.
usernamestringProxy username.
passwordstringProxy password.
whitelist_ipstring | nullIPv4 allowed without credentials.
rotation_urlstring | nullAdvanced only: link that rotates the exit IP. null on Standard and on expired proxies.
serverServerThe server this proxy runs on.
created_atstringPurchase time, ISO 8601 UTC.
expires_atstringExpiry time, ISO 8601 UTC.

Server

FieldTypeDescription
idintegerServer id.
countrystringISO 3166-1 alpha-2 country code.
regionstringState or region.
ispstringMobile carrier.
typestringMobile 5G, Mobile 4G, Residential or Datacenter.
planstringstandard or advanced. See Plans.
rotation_minutesinteger | nullHow often the exit IP rotates on its own. null when it only changes on request.
pricesarrayGET /servers only: { duration, price } for each duration code.

Errors

Errors use RFC 7807 with Content-Type: application/problem+json. Handle errors by type; detail is a readable explanation that can change wording.

Response · 402 Payment Required
{
  "type": "https://proxystream.net/docs/reseller-api#insufficient_balance",
  "title": "Insufficient balance",
  "status": 402,
  "detail": "This purchase costs 5.00 USD. Top up your balance and retry."
}
TypeStatusMeaningWhat to do
invalid_request400A parameter or the body is invalid.detail names the field. Fix it and retry.
unauthorized401The API key is missing, invalid or revoked.Check the Authorization header, or ask support for a new key.
insufficient_balance402Your balance does not cover the purchase. Nothing was charged.Top up your balance and retry.
not_found404No proxy with this id on your account.Check the id.
proxy_expired409Expired proxies cannot be changed or checked.Buy a new proxy.
server_unavailable409The server is full or offline. Nothing was charged.Pick another server from GET /servers.
username_taken409Another active proxy already uses this username.Choose a different username.
rate_limited429More than 120 requests in a minute.Wait Retry-After seconds.
internal_error500Unexpected failure on our side.Retry reads. Before retrying a purchase, check your proxy list.

The full type is this page's URL plus the code, e.g. https://proxystream.net/docs/reseller-api#server_unavailable.