Official Python SDK for the Webshare proxy API.
pip install webshare-sdk
Requires Python 3.10+. The only runtime dependency is httpx.
import webshare
with webshare.Webshare() as client: # reads WEBSHARE_API_KEY from the environment
for proxy in client.proxies.list(mode="direct"):
print(f"{proxy.proxy_address}:{proxy.port}")Async variant:
import asyncio
import webshare
async def main() -> None:
async with webshare.AsyncWebshare() as client:
page = await client.proxies.list(mode="direct")
async for proxy in page:
print(f"{proxy.proxy_address}:{proxy.port}")
asyncio.run(main())Most proxy operations are plan-scoped: they accept a plan_id and use an
account default when it is omitted. The standard pattern is to list your
plans, pick the one you want, and pass its id explicitly:
with webshare.Webshare() as client:
plan = next(p for p in client.plans.list() if p.status == "active")
proxies = client.proxies.list(mode="direct", plan_id=plan.id)
config = client.proxy_config.get(plan_id=plan.id)
stats = client.proxy_config.get_stats(plan_id=plan.id)
status = client.proxy_config.get_status(plan_id=plan.id)
url = client.proxies.download_url(config.proxy_list_download_token, plan_id=plan.id)The plan id is also visible in the dashboard URL when viewing a plan. The
active plan of the subscription is client.subscription.get().plan.
| Function | Description |
|---|---|
client.plans.list() |
List your plans; the ids scope most other calls. |
client.proxies.list(mode=..., plan_id=...) |
List proxies (paginated). |
client.proxies.download(token, plan_id=...) |
Download the proxy list as address:port:username:password text. |
client.proxy_config.get(plan_id=...) |
Get the proxy config (timeouts, IP-auth targeting, download token). |
client.stats.aggregate(plan_id=...) |
Aggregate proxy usage stats for a period. |
webshare.build_proxy_url(...) |
Build proxy connection URLs (backbone sessions/rotation or direct mode). |
See REFERENCE.md for every method.
Pass the API key explicitly, or set the WEBSHARE_API_KEY environment
variable:
client = webshare.Webshare(api_key="your-api-key")For advanced use (for example OAuth tokens that need refreshing), pass a
credentials_provider callable returning the token; it is called once per
request. The async client also accepts async callables. api_key is shorthand
for a static provider.
client = webshare.Webshare(credentials_provider=lambda: load_token())The constructor raises webshare.WebshareError when no credential is
available (empty strings are treated as absent). A handful of endpoints are
unauthenticated (for example client.referral.get_code_info and the download
URLs); the SDK never sends the token to them. To call only those without any
credential, construct the client with unauthenticated=True — authenticated
operations on such a client raise a clear error.
Every list method returns a page object exposing the raw envelope
(results, count, next, previous) and next_page(). Iterating the page
object yields items across all pages automatically:
page = client.proxies.list(mode="direct", page_size=100)
print(page.count) # total number of results
for proxy in page: # iterates across every page
...
next_page = page.next_page() # or fetch one page at a timeThe async client works the same way with async for and
await page.next_page().
All SDK errors derive from webshare.WebshareError. API failures raise a
status-specific subclass of webshare.APIError:
import webshare
try:
client.proxies.list(mode="direct")
except webshare.RateLimitError as err:
print(err.status_code, err.detail)
except webshare.PermissionDeniedError as err:
if err.code == "account_suspended":
... # see client.verification.get_suspension()
except webshare.APIError as err:
print(err.status_code, err.code, err.field_errors, err.request_id)| Exception | Status |
|---|---|
BadRequestError |
400 |
AuthenticationError |
401 |
PermissionDeniedError |
403 (check code: account_suspended, account_deleted) |
NotFoundError |
404 |
RateLimitError |
429 |
InternalServerError |
5xx |
ResponseDecodeError |
2xx with an undecodable body |
APIConnectionError / APITimeoutError |
transport failures |
Validation failures populate err.field_errors, e.g.
{"mode": ["This field is required."]} (both the documented string-list and
the live API's message-object forms are parsed). When the server sends a valid
Retry-After header, err.retry_after carries the parsed seconds so callers
can self-throttle calls the SDK does not retry (such as a 429 on POST). If you
authenticate with a login token via credentials_provider (rather than an API
key), calls can additionally return 403 with code 2fa_needed; API keys are
never 2FA-challenged.
Failed requests are retried automatically with exponential backoff and full
jitter (base 0.5s, cap 8s): connection errors, timeouts, 408, 429 and 5xx.
Retry-After headers are honored (capped at 60s). The default is
max_retries=2 (three attempts total), configurable per client and per
request. Only idempotent requests (GET/PUT/DELETE) are retried by default;
pass retry_non_idempotent=True to the client to opt in POST/PATCH.
The default request timeout is 60 seconds and bounds a single HTTP attempt,
including reading the response body; the total call time may exceed it when
retries and Retry-After waits occur. Override it per client
(Webshare(timeout=10.0)) or per request:
client.profile.get(timeout=5.0)If you inject your own http_client and do not set timeout, the injected
client's timeout configuration is used.
Every method also accepts per-request headers, max_retries, subuser_id
(sent as X-Subuser for sub-user masquerading) and federated_user_id (sent
as X-Webshare-Federated-Access, admin only); the last two can also be set on
the client.
webshare.build_proxy_url builds proxy connection URLs, including the
backbone username grammar for geo targeting, sticky sessions and rotation:
from webshare import build_proxy_url
# Backbone mode with country targeting and a sticky session
url = build_proxy_url(
username="user",
password="pass",
country_codes=["US"],
session_id=1234,
)
# -> "http://user-us-1234:pass@p.webshare.io:80"
# Direct mode using an entry from client.proxies.list()
url = build_proxy_url(
mode="direct",
username=proxy.username,
password=proxy.password,
proxy_address=proxy.proxy_address,
port=proxy.port,
)webshare.build_proxy_list_download_url (also available as
client.proxies.download_url) builds the unauthenticated proxy list download
URL from the config's proxy_list_download_token;
client.proxies.download(...) fetches it directly and returns the text.
Every request carries an X-Webshare-Source header identifying the caller
for API-side tracking. It names only the SDK and the Python runtime version
(default WebshareSDK/<version> (Python; <python version>)) — no user data.
Tools built on the SDK can replace it via the source client option, and
per-request headers override it as usual.
| Python | Supported |
|---|---|
| 3.10 / 3.11 / 3.12 / 3.13 | yes |
API reference: https://apidocs.webshare.io
MIT. Issues and pull requests are welcome.