Automating proxies over the API: whitelist, purchase and renewal from a script
IP authentication is more convenient than a password until the address changes. Once it is dynamic, the whitelist turns into manual work — and people give up on it, even though this is exactly the job one cron request closes. Below is how it works here, including the trap that costs people access to their own plan.
The key and its limits
The key travels in the Authorization header as a Bearer token. It is created in the dashboard and revoked there; a revoked key stops working immediately, so rotating keys needs no downtime: create a new one, switch the script, revoke the old one.
Worth knowing the limits before you hit them: 300 requests per minute and 5000 per hour per key. Two actions have their own, stricter limits: purchase at 60 per hour and credential retrieval at 30 per hour. The last one matters for scripts that fetch the login and password before every run: thirty an hour is plenty, but not for a loop over a hundred jobs.
The whitelist is replaced, not appended
This is the main trap, so it comes first. The whitelist request is a PUT, and it writes the list you send in place of the previous one rather than adding to it. A script that sends its own single address wipes every other entry: the server that was working on the whitelist loses access the moment a laptop refreshes its address.
KEY="..."; SVC="..."; ME=$(curl -s https://api.ipify.org)
# 1. Read the current list
curl -s -H "Authorization: Bearer $KEY" \
"https://op-proxy.com/api/v1/services/$SVC" \
| jq '.data.whitelist'
# 2. Replace only your own entry (by label), keep the rest
curl -s -X PUT -H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
"https://op-proxy.com/api/v1/services/$SVC/whitelist" \
-d "{\"whitelisted_ips\":[\"$ME\",\"203.0.113.10\"],\"labels\":[\"laptop\",\"ci\"]}" \
| jq '.data.whitelist'Limits better learned in advance
- No more than 50 addresses per service. Exceeding it returns too_many_ips and the list is left unchanged.
- IPv4 only. The address is validated as IPv4 and an IPv6 one is rejected with invalid_ip. If your machine's egress address is IPv6, the whitelist is not for you — use login and password.
- Labels are optional, trimmed to 64 characters and matched to addresses by position in the array.
- Duplicates in the list are dropped silently — a repeat is not an error.
- Only rotating services have a whitelist; any other type returns not_found.
A dynamic address: one call from cron
This is the job worth reaching for the API for. A script learns its current external address, compares it against what is recorded under its own label and, if it changed, sends the updated list. Once every five minutes from cron — and IP authentication stops being a problem on a home or mobile connection.
One reliability detail: compare before writing. An unconditional PUT every five minutes works, but it spends your limit and rewrites the list when nothing changed — which means any bug in how you build that list gets applied before you notice it.
Purchase and renewal
A purchase is a POST with the service type and a plan id; country and rotation mode are optional. There is an asymmetry worth remembering: for ipv4_rotating you must not send a country — those services always use one gateway, and you will get unsupported_for_type back. For ipv6_rotating the country is selectable.
# Available plans with their ids
curl -s -H "Authorization: Bearer $KEY" \
https://op-proxy.com/api/v1/catalog/plans | jq '.data'
# Purchase: send a country only for ipv6_rotating
curl -s -X POST -H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
https://op-proxy.com/api/v1/purchase \
-d '{"type":"ipv6_rotating","plan_id":"...","country":"de"}'
# Renewal debits the price from your balance
curl -s -X POST -H "Authorization: Bearer $KEY" \
"https://op-proxy.com/api/v1/services/$SVC/extend"Renewal debits the price from the account balance. If there is not enough, you get insufficient_balance with status 402 and the service is not extended. Debit and extension are tied together: if the extension fails the money goes back to the balance, so retrying after an error does not double-charge.
Rotation
The rotation mode is changed by a separate request and set as a short code. For ipv4_rotating there is no such request: rotation there is per request always, and trying to set a mode returns an error with an explanation rather than silently ignoring you. That is deliberate — silently ignoring a setting is worse than refusing it.
Errors arrive as codes, not prose
Every response carries a status field, and on failure a code plus a human-readable message. Branch on the code in your script: we may reword messages, we will not renumber codes. The practically useful ones: invalid_ip and too_many_ips on the whitelist, insufficient_balance on renewal, unsupported_for_type on an unsupported purchase combination, not_found for a service id that is not yours or does not exist.
The full description of every method is available machine-readable — the OpenAPI specification is served by the same API, so a client can be generated rather than hand-written.
The key is created in the dashboard
The API is available on every plan at no extra charge. Rotating IPv6 from 650 ₽ for 50 threads, IPv4 from 1375 ₽ for 100.
View pricingProxies for this job
Check it with our tools
Read next
- The program will not take a proxy login and password: which clients cannot send them, and what to doChromium has never supported SOCKS5 authentication, Android has no password field, netsh has no parameter. A breakdown by client, a one-command check, and the whitelist route around it.
- Proxy authentication by IP or by login: when to use whichThe two schemes solve different problems. Where a whitelist is the only option, where a password is safer, and why keeping both beats choosing.
- Authenticated proxies in Selenium: why every old recipe brokeAcross 2025 Chrome removed four separate things, and each one breaks a different line of the decade-old tutorial. What actually broke, what MV3 did not lose, and four routes that work today.
