herosms
Async and sync Python client for HeroSMS (SMS-Activate compatible API).
Features
- Async-first client with context-manager support
- Synchronous wrapper for non-async projects
- Activation lifecycle helpers (create, wait, resend, complete, cancel)
- Rent APIs support
- Reference data helpers (countries, services, operators, prices)
- Typed models with Pydantic v2
- Custom exception hierarchy
- Webhook payload parsing for incoming SMS events
Installation
pip install herosms
For development:
uv sync --extra dev
Quickstart (async)
import asyncio
from herosms import HeroSMSClient
async def main() -> None:
async with HeroSMSClient(api_key="YOUR_API_KEY") as client:
balance = await client.get_balance()
print(f"Balance: {balance}")
activation = await client.activations.create(service="tg", country=6)
print("Phone:", activation.phone) # available immediately
status = await activation.wait_for_sms(timeout=120)
print("Code:", status.code)
await activation.complete()
asyncio.run(main())
Quickstart (sync)
from herosms import SyncHeroSMSClient
with SyncHeroSMSClient(api_key="YOUR_API_KEY") as client:
balance = client.get_balance()
print(f"Balance: {balance}")
Response formats (response_format)
Most methods support response_format with three modes:
"model"(default): return typed Pydantic models / parsed structures."json": return transport payload as JSON-compatible value."raw": return raw API payload as plain string.
For endpoints that return legacy plain text (for example ACCESS_BALANCE:0.84 or STATUS_WAIT_CODE), response_format="json" wraps text into:
{"type": "text", "raw": "..."}
This keeps JSON mode consistent even when the upstream API responds with plain text.
HTTP debug logging
Enable HTTP debug logs when constructing the client:
from herosms import HeroSMSClient
client = HeroSMSClient(
api_key="YOUR_API_KEY",
debug=True,
log_body_max_length=500,
)
Parameters:
debug: enables request/response debug logs (herosms.httplogger).log_body_max_length: maximum number of response-body characters to log.log_body_max_length=None: disables trimming and logs full body.
Activation lifecycle
Manual mode (recommended, immediate phone)
activation = await client.activations.create(service="tg", country=6)
print(activation.phone) # available right after create
status = await activation.wait_for_sms(timeout=120)
print(status.code)
await activation.complete()
# or
await activation.cancel()
Async context manager mode (async with)
async with await client.activations.create(service="tg", country=6) as activation:
status = await activation.wait_for_sms(timeout=120)
print(status.code)
await activation.complete()
Continue existing activation by activation_id (attach)
activation = client.activations.attach(
activation_id=777001,
phone_number="79990009999", # optional
)
status = await activation.wait_for_sms(timeout=120)
print(status.code)
await activation.complete()
Request another SMS:
await activation.request_sms()
Get all OTP messages for activation:
messages = await activation.get_all_sms()
Legacy status endpoint (getStatus)
Use get_status_v1 if you need raw text-compatible status values from legacy integrations:
raw_status = await client.get_status_v1(activation_id=123456)
print(raw_status) # e.g. STATUS_WAIT_CODE or STATUS_OK:1234
Sync variant:
raw_status = client.get_status_v1(activation_id=123456)
Sync/async parity
Both clients expose the same core API surface:
HeroSMSClient(async) — use withawaitSyncHeroSMSClient(sync) — same method names withoutawait
Activation namespace parity (client.activations.*):
create(...)attach(...)list_active(...)get_active_activations(...)(alias oflist_active)get_history(...)finish(...)cancel(...)get_sms(...)
get_active_activations examples
Async:
active = await client.activations.get_active_activations(limit=10)
print(active)
Sync:
active = client.activations.get_active_activations(limit=10)
print(active)
History examples
Async:
history = await client.get_history(size=20)
print(history)
Sync:
history = client.get_history(size=20)
print(history)
Rent flow
Check availability:
Async:
availability = await client.get_rent_availability(service="tg", country=6)
print(availability)
Sync:
availability = client.get_rent_availability(service="tg", country=6)
print(availability)
Rent a number:
Async:
rent_activation = await client.rent_number(service="tg", country=6, duration=2)
print(rent_activation.phone)
Sync:
rent_activation = client.rent_number(service="tg", country=6, duration=2)
print(rent_activation.phone)
Reference data APIs
countries = await client.get_countries()
services = await client.get_services(country=6)
operators = await client.get_operators(country=6)
prices = await client.get_prices(service="tg", country=6)
top = await client.get_top_countries(service="tg", by_rank=True)
Error handling
All library exceptions inherit from HeroSMSError.
from herosms import HeroSMSError
try:
...
except HeroSMSError as exc:
print(f"HeroSMS error: {exc}")
Webhook payload parsing (smsIncoming)
Parse and validate incoming webhook payload with Pydantic model:
from herosms import WebhookSMSIncoming
payload = {
"activationId": "635468024",
"service": "tg",
"text": "Telegram code 123456",
"code": "123456",
"country": 6,
"receivedAt": "2026-02-16T12:36:59+03:00",
}
event = WebhookSMSIncoming.model_validate(payload)
print(event.activation_id, event.code)
API compatibility note
HeroSMS is compatible with SMS-Activate-style API actions. This library targets HeroSMS endpoints while preserving familiar SMS-Activate action semantics.
Metadata
Release files for herosms 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| herosms-0.1.1.tar.gz | 75.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| herosms-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 98.0 kB
Release files / herosms-0.1.1.tar.gz
| Download URL | herosms-0.1.1.tar.gz |
|---|---|
| Size | 75.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1afb59b46da3b462cf3dd76f6197c6b81d456fea176358c95cd0c4d6c520ad0f
|
|
BLAKE2b-256 checksum How to use checksums |
0a688b61c07e0f78bc97c8e0aee8b3abf40943d5014c6179e4497131898b2558
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.8
|
Release files / herosms-0.1.1-py3-none-any.whl
| Download URL | herosms-0.1.1-py3-none-any.whl |
|---|---|
| Size | 22.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1ed8392ec930d5867a1a0a54abb6e18ff488f603cbad5d7791debe6dc6aa368b
|
|
BLAKE2b-256 checksum How to use checksums |
487e453847dc50f08d1f9aaa13ddbb185b865a86010753a16528502767e90172
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.8
|
Security for herosms 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.