Skip to content
Log In Sign up

ISP Proxies API

Everything you can do on an ISP Proxies plan page in the panel is also available over this API: search the locations you can place IPs on, list every proxy with its username, place the IPs you have not placed yet, and move IPs to another city or ISP.

All endpoints authenticate with an api_token query parameter. Generate a token in the panel under Account → API Tokens.

?api_token=YOUR_API_TOKEN

Every path starts with https://shifter.io/api/v1/isp/{membership}. The {membership} path parameter accepts either form of the plan identifier: the short code at the end of the plan’s panel URL (for example Rxqk) or the plan number shown on the plan page (for example 68057). Both resolve to the same plan.

The API only reaches ISP Proxies plans that belong to the owner of the token. Any other plan answers 404.

  • Each IP can change location 5 times per billing period. The count resets when the plan renews, and unused changes do not carry over to the next period. This applies to trials too.
  • A moved IP gets a new username and a new proxy_id. The old username stops working immediately, so switch your clients to the new one right away.
  • The plan password stays the same. There is one password per plan, shared by every username on it.
  • Usernames are case-sensitive. Every proxy connects through isp.shifter.io:443, over HTTP(S) or SOCKS5.
  • Each IP keeps the city and ISP you chose. The address behind it can refresh now and then, the same way a home connection gets a new address from its ISP.
GET https://shifter.io/api/v1/isp/{membership}/locations

Returns the city and ISP pairs you can place IPs on, with how many IPs are available on each right now. Locations with nothing available are left out unless you ask for them.

ParameterInRequiredDescription
membershippathyesThe plan ID (short code or plan number)
api_tokenqueryyesYour account API token
countryquerynoISO 3166-1 alpha-2 country code, e.g. US
qquerynoSearch text: a city (local names work too), a region, an ISP name, or an ASN such as 7922 or AS7922
pagequerynoPage number, starting at 1
per_pagequerynoResults per page, default 100, maximum 500
include_sold_outquerynoSet to 1 to include locations with no IPs available

Example:

Terminal window
curl "https://shifter.io/api/v1/isp/YOUR_PLAN_ID/locations?country=US&q=Dallas&api_token=YOUR_API_TOKEN"

Response:

{
"ok": true,
"page": 1,
"per_page": 100,
"total": 2,
"has_more": false,
"locations": [
{
"location_id": 1842,
"country": "US",
"region": "Texas",
"city": "Dallas",
"asn": 7922,
"isp": "COMCAST-7922",
"available": 7
}
]
}

location_id is stable, so you can store it and reuse it later. available is the number of IPs you can place on that location right now. Use has_more to know when to request the next page.

GET https://shifter.io/api/v1/isp/{membership}/proxies

Returns the connection details for the plan and every placed IP with its username, location and remaining location changes.

ParameterInRequiredDescription
membershippathyesThe plan ID (short code or plan number)
api_tokenqueryyesYour account API token

Example:

Terminal window
curl "https://shifter.io/api/v1/isp/YOUR_PLAN_ID/proxies?api_token=YOUR_API_TOKEN"

Response:

{
"ok": true,
"host": "isp.shifter.io",
"port": 443,
"password": "YOUR_PLAN_PASSWORD",
"ips_total": 10,
"ips_placed": 3,
"ips_unplaced": 7,
"changes_per_ip": 5,
"period_ends_at": "2026-10-20T08:00:00+00:00",
"proxies": [
{
"proxy_id": 5531,
"username": "us-texas-dallas-as7922-Ksj25",
"location_id": 1842,
"country": "US",
"region": "Texas",
"city": "Dallas",
"asn": 7922,
"isp": "COMCAST-7922",
"changes_left": 5
}
]
}
FieldDescription
host / portWhere every proxy on the plan connects
passwordThe plan password, shared by every username
ips_totalIPs included in the plan
ips_placed / ips_unplacedIPs already on a location, and IPs you can still place
changes_per_ipLocation changes each IP gets per billing period
period_ends_atWhen the current billing period ends and the changes reset
proxies[].usernameThe username to connect with. Case-sensitive
proxies[].ispThe ISP name for the ASN. Can be null when no name is known
proxies[].changes_leftLocation changes this IP has left in the current period

To connect, combine the fields into a proxy URL:

http://us-texas-dallas-as7922-Ksj25:YOUR_PLAN_PASSWORD@isp.shifter.io:443
socks5://us-texas-dallas-as7922-Ksj25:YOUR_PLAN_PASSWORD@isp.shifter.io:443
POST https://shifter.io/api/v1/isp/{membership}/proxies/{proxy_id}/location

Moves one IP to another location. This uses one of that IP’s location changes.

ParameterInRequiredDescription
membershippathyesThe plan ID (short code or plan number)
proxy_idpathyesThe proxy_id of the IP to move
api_tokenqueryyesYour account API token
location_idbodyyesThe location to move the IP to

Example:

Terminal window
curl -X POST "https://shifter.io/api/v1/isp/YOUR_PLAN_ID/proxies/5531/location?api_token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"location_id":1901}'

Response:

{
"ok": true,
"message": "Location changed. Use the new username from now on.",
"old_proxy_id": 5531,
"proxy": {
"proxy_id": 5534,
"username": "us-texas-austin-as7018-Pq7rT",
"location_id": 1901,
"country": "US",
"region": "Texas",
"city": "Austin",
"asn": 7018,
"isp": "ATT-INTERNET4",
"changes_left": 4
}
}

The IP now has a new proxy_id and a new username. The old username (and old_proxy_id) stop working as soon as the response arrives.

POST https://shifter.io/api/v1/isp/{membership}/proxies/location

Moves several IPs in one request, each to the location you name for it.

ParameterInRequiredDescription
membershippathyesThe plan ID (short code or plan number)
api_tokenqueryyesYour account API token
movesbodyyesArray of {"proxy_id", "location_id"} pairs, at most 1,000 per request
dry_runbodynotrue to check the request without changing anything. Default false
  • The request is all or nothing: if any move cannot be made, no IP moves and you get an error.
  • An entry whose IP is already on its target location is skipped and does not use a change. Its proxy_id is listed in skipped.
  • With dry_run: true nothing is written. The response shows what would happen, with proxy_id and username set to null in moved, since the new ones only exist once the move is real.

Example:

Terminal window
curl -X POST "https://shifter.io/api/v1/isp/YOUR_PLAN_ID/proxies/location?api_token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"moves":[{"proxy_id":5531,"location_id":1901},{"proxy_id":5532,"location_id":1842}],"dry_run":false}'

Response:

{
"ok": true,
"dry_run": false,
"message": "1 IP moved. Use the new username from now on. 1 IP was already there and stays as it is.",
"moved": [
{
"old_proxy_id": 5531,
"proxy_id": 5535,
"username": "us-texas-austin-as7018-Zt3wQ",
"location_id": 1901,
"country": "US",
"region": "Texas",
"city": "Austin",
"asn": 7018,
"isp": "ATT-INTERNET4",
"changes_left": 4
}
],
"skipped": [5532]
}
POST https://shifter.io/api/v1/isp/{membership}/proxies/place

Places IPs that are not on a location yet (ips_unplaced in the proxy list). Placing an IP does not use a location change.

ParameterInRequiredDescription
membershippathyesThe plan ID (short code or plan number)
api_tokenqueryyesYour account API token
placementsbodyyesArray of {"location_id", "count"} pairs: how many IPs to place on each location

Example:

Terminal window
curl -X POST "https://shifter.io/api/v1/isp/YOUR_PLAN_ID/proxies/place?api_token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"placements":[{"location_id":1901,"count":2}]}'

Response:

{
"ok": true,
"message": "2 IPs are ready.",
"placed": 2,
"ips_unplaced": 5,
"proxies": [
{
"proxy_id": 5540,
"username": "us-texas-austin-as7018-Hh8aa",
"location_id": 1901,
"country": "US",
"region": "Texas",
"city": "Austin",
"asn": 7018,
"isp": "ATT-INTERNET4",
"changes_left": 5
}
]
}

Find a location in Austin, move two IPs there, and read back the usernames to use from now on. This uses jq to read the JSON.

Terminal window
TOKEN="YOUR_API_TOKEN"
PLAN="YOUR_PLAN_ID"
BASE="https://shifter.io/api/v1/isp/$PLAN"
# 1. Find a location with IPs available
LOCATION=$(curl -s "$BASE/locations?country=US&q=Austin&api_token=$TOKEN" \
| jq '.locations[0].location_id')
# 2. Move two IPs there
curl -s -X POST "$BASE/proxies/location?api_token=$TOKEN" \
-H "Content-Type: application/json" \
-d "{\"moves\":[{\"proxy_id\":5531,\"location_id\":$LOCATION},{\"proxy_id\":5532,\"location_id\":$LOCATION}]}" \
| jq -r '.moved[].username'
# 3. Read every current username and build proxy URLs
curl -s "$BASE/proxies?api_token=$TOKEN" \
| jq -r '.password as $p | .proxies[] | "http://\(.username):\($p)@isp.shifter.io:443"'

Update your clients with the new usernames from step 2 or 3 straight away: the old ones stop working as soon as the move completes.

A failed request returns "ok": false with a machine-readable error code and a readable message:

{
"ok": false,
"error": "plan_inactive",
"message": "This plan is not active, so locations cannot be assigned."
}
StatuserrorMeaning
404not_foundThe plan or IP does not exist on your account. May include proxy_ids
422validationA parameter is missing or invalid
422no_changes_leftOne or more IPs have used all their location changes for this period. Includes proxy_ids
409out_of_stockA location does not have enough IPs available. Includes location_id and available
409plan_inactiveThe plan is not active, so its IPs cannot be placed or moved
RequestsLimit
Reads (GET)60 per minute per account
Writes (POST)20 per minute per account

Past the limit the API answers 429. Wait and retry with backoff. To move many IPs, send them in one Move many IPs request instead of one request per IP.