Skip to main content

Official Eveses SDK for the /api/v1 surface — numbers, wallet, proxy, web-unblocker, emails, trial, captcha, orders, pricing, quotas, webhooks.

Project description

eveses (Python SDK)

Official Python SDK for the Eveses developer API, built for the versioned /api/v1 surface. Numbers (SMS activations/rentals + catalog), wallet, proxies, web-unblocker, temporary emails, free trials, captcha-solving, a unified orders feed, aggregate pricing / quotas, the me principal, and webhook signature verification.

Install

pip install eveses

Requires Python 3.9+ and requests.

Quickstart

import os
from eveses import Eveses

client = Eveses(api_key=os.environ["EVESES_API_KEY"])

order = client.numbers.create(
    country="ua",
    service="telegram",
    idempotency_key="my-uuid",
)
print(order.order_id, order.phone)

wallet = client.wallet.balance()
print(f"{wallet.available_balance / 100} {wallet.currency}")

Authentication

Every request sends Authorization: Bearer <api_key>. Generate an API key from your dashboard (Settings → API keys). The token is a Sanctum personal-access token with kind=api_key.

Numbers (SMS activations / rentals + catalog)

The former activations and catalog namespaces are merged into one numbers module under /api/v1/numbers/*.

order = client.numbers.create(
    country="ua",
    service="telegram",
    mode="activation",            # or "rent"
    duration_minutes=60,          # rent only
    max_price_cents=100,          # optional ceiling
    idempotency_key="my-uuid",    # also sent as Idempotency-Key header
)

fresh = client.numbers.get(order.order_id)
sms   = client.numbers.sms(order.order_id)
#   sms.stored — delivered to us via upstream webhook
#   sms.fresh  — pulled from upstream provider on demand

client.numbers.cancel(order.order_id)   # refund-where-supported
client.numbers.finish(order.order_id)   # mark consumed
client.numbers.retry(order.order_id)    # ask for another SMS
client.numbers.repeat(order.order_id)   # re-order the same country/service
client.numbers.auto_renew(order.order_id, True)   # rentals

client.numbers.list(status="active")    # native per-service history
client.numbers.summary()                # aggregate counts / totals
client.numbers.batch([{"country": "ua", "service": "telegram"}])

Catalog (countries / services / pricing)

Read-only metadata for driving order-creation UX, on the same module:

countries = client.numbers.countries(mode="activation").countries
services  = client.numbers.services(mode="activation", country="ua").services
pricing   = client.numbers.pricing(mode="activation", country="ua", service="telegram")
#   pricing.services[0].durations[0].price_cents → 50

client.numbers.carriers(country="us")   # operators for a country
client.numbers.states(country="us")     # states/regions where supported

mode accepts "activation" or "rent". For rentals, pass duration_minutes=... to pricing(...) to filter to a single duration. (services is an alias of products.)

Proxies

Buy and manage residential (metered, per-GB) and static (per-IP: ISP / datacenter / IPv6 / sneaker / mobile) proxies. The upstream provider stays invisible — connection details come back on the white-label host. Hits /api/v1/proxy/*.

# Browse
client.proxy.pricing()                         # residential GB ladder + static catalogue
client.proxy.endpoints()                       # white-label subdomains + ports
client.proxy.locations(type="residential")     # available targeting
client.proxy.quote(type="residential", gb=5)   # estimate before buying

# Buy
order = client.proxy.purchase(
    type="residential",
    gb=5,
    subscription=False,          # start a monthly residential subscription
    idempotency_key="my-uuid",
)
# static per-IP:
# client.proxy.purchase(type="isp", product_id=1, plan_id=2, location_id=3, quantity=2)

# Manage
listing = client.proxy.list()                  # residential + subscription + orders
one     = client.proxy.get(order.uuid)          # a single order by UUID
client.proxy.usage(from_="2026-06-01", to="2026-06-24")
client.proxy.extend(order.uuid, days=30)        # static per-IP order
client.proxy.auto_renew(order.uuid, enabled=True)
client.proxy.reset_sessions()                   # rotate residential sticky sessions
client.proxy.trial()                            # one-time proxy free trial

# Residential subscription
client.proxy.subscription_pause()
client.proxy.subscription_resume()
client.proxy.subscription_cancel()

Web Unblocker

Buy and manage a web-unblocker subscription (metered by request count). Hits /api/v1/webunblocker/*.

client.web_unblocker.pricing()
client.web_unblocker.quote(10_000, subscription=False)
client.web_unblocker.access()                   # credentials + endpoints

client.web_unblocker.purchase(10_000, subscription=False, idempotency_key="my-uuid")
client.web_unblocker.trial()                    # one-time free trial

client.web_unblocker.subscription_pause()
client.web_unblocker.subscription_resume()
client.web_unblocker.subscription_cancel()

Emails

Buy and manage temporary email addresses and browse received messages. Hits /api/v1/emails/*.

client.emails.pricing(site="example.com")        # domains under the `domains` key
client.emails.quote("mail.example", provider="…")

box = client.emails.purchase("mail.example", idempotency_key="my-uuid")
address = box["email"]

client.emails.list(include_released=False)
client.emails.get(address)
client.emails.messages(address, page=1, per_page=20)
client.emails.mark_read(address, message_id=123)
client.emails.release(address)                   # delete the address

Trial

Query and activate free-trial access for individual services. Hits /api/v1/trial/*.

client.trial.status()                            # eligibility / used / expires_at
client.trial.subscribe(["telegram", "whatsapp"])

Captcha

Resells 2captcha, billed pay-per-use from the wallet (count-on-success). The solve call is blocking: it submits the task then polls the result endpoint — honouring the API's retry_after — until the task is ready. Hits /api/v1/captcha/*.

solution = client.captcha.solve(
    "recaptcha_v2",
    {"sitekey": "…", "pageurl": "https://example.com"},
    idempotency_key="my-uuid",
    timeout_sec=180,
)
print(solution.solution, solution.price_micro_usd)
# raises EvesesError on failure or timeout

client.captcha.result(task_id)   # single, non-blocking poll
client.captcha.rates()           # per-solve retail rates by type
client.captcha.usage(status="ready")   # cursor-paginated task history

Orders, pricing, quotas

Cross-product read surfaces for dashboards.

# Unified order history (numbers | proxy | webunblocker | emails; NOT captcha)
feed = client.orders.list(service="proxy,emails", status="active", limit=50)
one  = client.orders.get("b1f2…-uuid")     # normalized OrderView for any product

prices = client.pricing.all()               # every product's prices in one call
quotas = client.quotas.all()                # remaining prepaid balances

Me

me = client.me.get()
print(me.abilities)          # e.g. ["*"]
print(me.features)           # {"trial": True, "proxy": True, "captcha": False, …}
# Use me.features to gate product entry points instead of build-time flags.

client.me.loyalty()          # loyalty tier / weekly-spend status

Webhook verification

Eveses signs every outbound webhook delivery with HMAC-SHA256 over f"{timestamp}.{raw_body}". Two headers carry the proof:

  • X-Eveses-Signature — e.g. sha256=abc123…
  • X-Eveses-Timestamp — unix seconds

Pass the raw request body (bytes or str) — not the parsed JSON. Re-serialising through json.loads / json.dumps reorders keys and breaks the signature.

# Flask example
from flask import Flask, request
from eveses import Webhooks

app = Flask(__name__)
SECRET = os.environ["EVESES_WEBHOOK_SECRET"]

@app.post("/eveses-webhook")
def eveses_webhook():
    raw = request.get_data()  # bytes
    if not Webhooks.verify(
        raw,
        request.headers.get("X-Eveses-Signature"),
        SECRET,
        timestamp=request.headers.get("X-Eveses-Timestamp"),
    ):
        return "bad signature", 401

    payload = request.get_json()
    # handle payload["event"] / payload["data"] …
    return "", 204

A functional alias is also exported:

from eveses import verify_webhook
ok = verify_webhook(raw, sig_header, SECRET, timestamp=ts_header)

Errors

All non-2xx responses raise a typed subclass of EvesesError:

Status Class
400 / 422 EvesesValidationError (with .errors)
401 EvesesAuthError
403 EvesesForbiddenError
404 EvesesNotFoundError
429 EvesesRateLimitError (only after the 1 auto-retry is exhausted)
5xx EvesesServerError
other EvesesError
from eveses import EvesesValidationError

try:
    client.numbers.create(country="", service="")
except EvesesValidationError as e:
    print(e.errors)

API surface

Every authenticated call targets the versioned /api/v1/* surface. The base URL is unchanged (…/api); only the per-call path string changed from the old /api/account/* scope. Auth is unchanged — keep sending the Sanctum bearer token. Every /v1 response also carries RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset headers (plus Retry-After on a 429) for backoff.

Configuration

client = Eveses(
    api_key="…",
    base_url="https://api.eveses.com",  # override per environment
    timeout=30.0,
    session=requests.Session(),         # inject for tests / connection pooling
    default_headers={"X-Trace-Id": "t1"},
    user_agent="my-app/1.2.3",
)

Development

pip install -e '.[dev]'
python -m pytest

Changelog

0.4.0

  • Repointed the whole SDK to the versioned /api/v1/* surface (from the legacy /api/account/* scope).
  • Merged activations + catalog → one numbers namespace under /api/v1/numbers/*: create, get, sms, cancel, finish, retry, repeat, auto_renew, list, summary, batch, plus catalog pricing, countries, products/services, carriers, states.
  • proxy/api/v1/proxy/*: buy/list on /orders, get(uuid), extend/auto_renew under /orders/{uuid}, and pricing (replaces the old packages/catalog).
  • web_unblocker/api/v1/webunblocker/*: buy/list on /orders, pricing.
  • emails/api/v1/emails/*: buy/list on /orders, pricing; inbox keyed by email address.
  • captcha/api/v1/captcha/*; added result, rates, and usage.
  • New orders namespace — unified cross-product order history (GET /api/v1/orders, …/{uuid}).
  • New pricing namespace — aggregate price sheet (GET /api/v1/pricing).
  • New quotas namespace — remaining prepaid balances (GET /api/v1/quotas).
  • New me namespace — the principal, now carrying abilities + features.
  • Removed the fingerprints product entirely.

0.3.0

  • New proxy namespace: residential (per-GB) and static per-IP proxies — packages, endpoints, catalog, locations, quote, usage, list, purchase, extend, auto_renew, reset_sessions, trial, and residential subscription pause/resume/cancel. Exposes Proxy, ProxyOrder, ProxySubscription, ProxyList.
  • New web_unblocker namespace: packages, quote, access, purchase, trial, and subscription pause/resume/cancel.
  • New emails namespace: temporary email addresses — domains, quote, list, get, messages, purchase, mark_read, release.
  • New trial namespace: status and subscribe for per-service free trials.
  • New captcha namespace: blocking solve (submit + poll) reselling 2captcha, billed pay-per-use. Exposes Captcha, CaptchaSolution.
  • New fingerprints namespace: synchronous generate / random browser fingerprints. Exposes Fingerprints, Fingerprint.
  • Module reorg: the old proxies module was replaced by proxy.

0.2.0

  • Activations, wallet, catalog (countries / services / pricing), and webhook signature verification.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

eveses-0.4.0.tar.gz (22.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

eveses-0.4.0-py3-none-any.whl (25.3 kB view details)

Uploaded Python 3

File details

Details for the file eveses-0.4.0.tar.gz.

File metadata

  • Download URL: eveses-0.4.0.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for eveses-0.4.0.tar.gz
Algorithm Hash digest
SHA256 cc7222c7396ceb172d8739ad7eb1268015881dddcfa9a12dbff982b6fbba34d7
MD5 8b9224e7452151028d46e37d7f0b8f26
BLAKE2b-256 b7de7290830e5580781ea0d9ed038e5de17bec2e4bc1f9864f7fd75410c4cc62

See more details on using hashes here.

File details

Details for the file eveses-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: eveses-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 25.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for eveses-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 050fcde5fb4c3dbf82cfb0f1693b0791ef03ad736453fa8e943af17da91c03eb
MD5 6194b669aaea490c2de46606f104a82e
BLAKE2b-256 df3155efe9538a99dd73350c7ff4861cbd5d5444d334ed51098b576c75c2c19a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page