Python client library for the Etoneya Subscription Management API.
Project description
Etoneya API Client
Fully-typed Python client for the Etoneya Subscription Management API. Ships
both a synchronous (EtoneyaClient) and asynchronous (AsyncEtoneyaClient)
flavour built on top of httpx.
Highlights
- 🔁 Sync + async clients with identical APIs
- 🧱 Typed dataclass models — including
BanCheckResultandHealthInfo - 🚦 Granular exceptions mapped from HTTP status codes (401/403, 404, 4xx, 409, 429, 5xx, transport)
- 🧰 Context-manager support (
with/async with) - 🧪 First-class testability — built around
httpx.MockTransport - 📦 PEP 561 typed (
py.typedshipped)
Installation
Requires Python 3.10+.
pip install etoneya-api
Or from source:
git clone https://github.com/keys-nloverx/etoneya-lib.git
cd etoneya-lib
pip install -e ".[dev]"
Quick start
Synchronous
from etoneya import EtoneyaClient
with EtoneyaClient(
base_url="https://api.example.com",
auth_token="your_auth_token_here",
) as client:
user = client.create_user(
tg_id=123456789,
type_sub="premium",
udid="udid-1",
limit_devices=3,
)
print(user.id)
info = client.health_check()
print(info.status, info.build)
Asynchronous
import asyncio
from etoneya import AsyncEtoneyaClient
async def main() -> None:
async with AsyncEtoneyaClient(
base_url="https://api.example.com",
auth_token="your_auth_token_here",
) as client:
info = await client.health_check()
print(info.status)
asyncio.run(main())
API surface
User management
client.create_user(tg_id=..., type_sub="premium", udid="...", limit_devices=3)
client.get_user(1)
client.get_user_by_telegram(123456789)
client.list_users() # all users
client.list_users(filter="active") # active only
client.list_users(filter="banned") # banned only
client.update_user(1, limit_devices=5)
client.ban_user(1, reason="Spam")
client.unban_user(1)
client.delete_user(1)
The legacy aliases get_all_users, get_active_users, and
get_banned_users are kept for backwards compatibility.
Devices
client.get_device(1)
client.get_device_by_hwid("hwid-1")
client.get_user_devices("udid-1")
client.delete_device(1)
IP bans
client.create_ip_ban("192.168.1.1", reason="abuse")
result = client.check_ip_ban("192.168.1.1")
if result.is_banned:
print(result.ban_info.reason)
client.get_all_bans()
client.delete_ip_ban(1)
client.delete_ip_ban_by_address("192.168.1.1")
System
info = client.health_check() # HealthInfo
client.update_subscriptions("hook-token")
Error handling
from etoneya import (
AuthenticationError,
ConflictError,
EtoneyaAPIError,
NotFoundError,
RateLimitError,
ServerError,
TransportError,
ValidationError,
)
try:
client.get_user(999)
except NotFoundError as exc:
print(exc.status_code, exc.message, exc.response)
except AuthenticationError:
...
except RateLimitError:
...
except TransportError:
# connection refused / timeouts / DNS — preserves the underlying httpx error
...
except EtoneyaAPIError:
...
| HTTP status | Exception |
|---|---|
| 400, 422 | ValidationError |
| 401, 403 | AuthenticationError |
| 404 | NotFoundError |
| 409 | ConflictError |
| 429 | RateLimitError |
| 5xx | ServerError |
| transport | TransportError |
| anything else | EtoneyaAPIError |
Models
All models are slotted, keyword-only dataclasses; convert to/from JSON-style
dicts via from_dict / to_dict.
@dataclass(slots=True, kw_only=True)
class User:
id: int
tg_id: int
type_sub: str
udid: str
limit_devices: int
reason: str = ""
is_banned: bool = False
is_active: bool = True
allowed_useragents: list[str] = []
status: str = "user" # "user" | "volunteer"
Device, BannedIP, BanCheckResult, and HealthInfo follow the same
pattern.
Configuration
import httpx
EtoneyaClient(
base_url="https://api.example.com",
auth_token="...",
timeout=httpx.Timeout(10.0, read=30.0),
user_agent="my-bot/1.0",
)
You can also inject a custom httpx.BaseTransport (or
httpx.AsyncBaseTransport) — handy for tests, retries via httpx-retries, or
custom proxying.
Development
git clone https://github.com/keys-nloverx/etoneya-lib.git
cd etoneya-lib
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pre-commit install
ruff check .
black --check .
mypy etoneya/
pytest
The CI matrix runs lint + type-check + tests on Python 3.10 – 3.13 across Linux/macOS/Windows.
License
MIT — see LICENSE.
Contact
- Author: nloverx (
owner@nloverx.best) - Telegram: @nloverx
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file etoneya_api-0.2.0.tar.gz.
File metadata
- Download URL: etoneya_api-0.2.0.tar.gz
- Upload date:
- Size: 14.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93aabdcfafb2d70ccf67ec157980db0f0b51e6be47e8428ffcdad4043d01d7ad
|
|
| MD5 |
a76556dddbfc4689b2e525daad8219f5
|
|
| BLAKE2b-256 |
5359e17a1851f6891ace58298c43dbd33a85c81806d51962cc9bec4acab98684
|
File details
Details for the file etoneya_api-0.2.0-py3-none-any.whl.
File metadata
- Download URL: etoneya_api-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
947617677c0359190d40a4d2a94f71bfeaa0531a4353d5ca5f0fd2cdbfce028e
|
|
| MD5 |
253a446f5855d69b3320765dc68df1f3
|
|
| BLAKE2b-256 |
83b75251fe1f86561a5566a5acf8578564e12e05ba2f464d3557bb909d1b58b1
|