Skip to content

ragnarok22/cryptobot_python

Repository files navigation

CryptoBot Python

PyPI version Python tests pre-commit.ci status Documentation Status codecov Ask DeepWiki

Unofficial but friendly Python client for the Crypto Bot API. It provides typed models, sane defaults, and synchronous/async clients for invoices, transfers, balances, exchange rates, and webhook handling.

Features

  • Synchronous httpx-based API client (CryptoBotClient)
  • Async httpx-based API client (AsyncCryptoBotClient)
  • Dataclass models for API responses (Invoice, Transfer, Balance, ExchangeRate, Currency)
  • Enum guard rails for assets, statuses, and paid button names
  • Mainnet/testnet support with configurable timeouts and retries
  • FastAPI-powered webhook listener with signature verification and optional replay protection
  • Custom exception model (CryptoBotError) with API code/name fields

What's New in 0.5.0

  • Added AsyncCryptoBotClient with method parity and async invoice iterators
  • Added invoice pagination helpers: iter_invoice_pages(...) and iter_invoices(...)
  • Added configurable retries/backoff (max_retries, retry_backoff, retryable_status_codes)
  • Added webhook replay protection (replay_store, replay_ttl_seconds, replay_key_resolver)

Installation

CryptoBot Python supports Python >=3.9.12.

pip install cryptobot-python

Install webhook server dependencies only when needed:

pip install "cryptobot-python[webhook]"

Install documentation tooling extras only when needed:

pip install "cryptobot-python[docs]"

Quick Start

import os

from cryptobot import CryptoBotClient
from cryptobot.models import Asset

client = CryptoBotClient(
    api_token=os.environ["CRYPTOBOT_API_TOKEN"],
    is_mainnet=True,
    timeout=5.0,
    max_retries=2,
    retry_backoff=0.5,
)

app = client.get_me()
print(app.name)

invoice = client.create_invoice(
    asset=Asset.USDT,
    amount=5.25,
    description="Coffee order #42",
)

print(invoice.invoice_id, invoice.bot_invoice_url)

To use testnet instead of mainnet:

client = CryptoBotClient(api_token=os.environ["CRYPTOBOT_TESTNET_TOKEN"], is_mainnet=False)

Retry behavior is optional and disabled by default (max_retries=0). The default retryable status codes are 429, 500, 502, 503, 504.

client = CryptoBotClient(
    api_token=os.environ["CRYPTOBOT_API_TOKEN"],
    max_retries=3,
    retry_backoff=0.5,
    retryable_status_codes={429, 500, 502, 503, 504},
)

Async usage:

import asyncio
import os

from cryptobot import AsyncCryptoBotClient
from cryptobot.models import Asset


async def main():
    async with AsyncCryptoBotClient(api_token=os.environ["CRYPTOBOT_API_TOKEN"], max_retries=2) as client:
        app = await client.get_me()
        print(app.name)

        invoice = await client.create_invoice(asset=Asset.USDT, amount=5.25, description="Async order #42")
        print(invoice.invoice_id, invoice.bot_invoice_url)


asyncio.run(main())

Core API

CryptoBotClient methods:

  • get_me()
  • create_invoice(...)
  • get_invoices(...)
  • transfer(...)
  • get_balances()
  • get_exchange_rates()
  • get_currencies()
  • iter_invoice_pages(...)
  • iter_invoices(...)

AsyncCryptoBotClient provides the same methods with await, plus async iterators for iter_invoice_pages(...) and iter_invoices(...).

get_invoices(...) accepts invoice_ids as a comma-separated string ("1,2,3") or list[int] ([1, 2, 3]). Iterator helpers accept page_size and start_offset to support controlled pagination scans.

Example transfer with idempotency via spend_id:

from cryptobot.errors import CryptoBotError
from cryptobot.models import Asset

try:
    transfer = client.transfer(
        user_id=123456789,
        asset=Asset.TON,
        amount=0.5,
        spend_id="reward_2026_02_10_user_123456789",
        comment="Cashback reward",
    )
    print(transfer.transfer_id, transfer.status)
except CryptoBotError as exc:
    print(exc.code, exc.name)

Webhooks

Use the built-in listener to validate incoming signatures and process updates:

import os

from cryptobot.webhook import InMemoryReplayKeyStore, Listener


def handle_webhook(headers, data):
    if data.get("update_type") == "invoice_paid":
        payload = data.get("payload", {})
        print("Paid invoice:", payload.get("invoice_id"))


listener = Listener(
    host="0.0.0.0",
    callback=handle_webhook,
    api_token=os.environ["CRYPTOBOT_API_TOKEN"],
    replay_store=InMemoryReplayKeyStore(),
    replay_ttl_seconds=3600,
    port=2203,
    url="/webhook",
    log_level="info",
)
listener.listen()

Listener accepts both sync and async callback functions. For custom dedupe behavior, pass replay_key_resolver(data, raw_body, headers) with a stable key strategy.

For custom webhook stacks, use cryptobot.webhook.check_signature(...) to verify crypto-pay-api-signature against the raw request body.

Development

uv sync
make lint
make test
make docs

Documentation

Contributing

Issues and pull requests are welcome. Before opening a PR:

make lint
make test

See CONTRIBUTING.md and AGENTS.md for project workflow and coding standards.

Credits

This project started with Cookiecutter and the audreyr/cookiecutter-pypackage template.

About

Non official, but friendly CryptoBot library for the Python language.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors 6