Skip to content

ragnarok22/cryptobot_python

Repository files navigation

CryptoBot Python

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

Unofficial but friendly Python client for the Crypto Bot API (v1.0 - stable). It provides typed models, sane defaults, and synchronous/async clients for invoices, transfers, checks, balances, exchange rates, statistics, and webhook handling.

Features

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

Installation

Requires Python 3.10+.

Using uv (recommended)

uv add cryptobot-python

Using pip

pip install cryptobot-python

Extras

Install webhook server dependencies (FastAPI + Uvicorn) only when needed:

uv add "cryptobot-python[webhook]"
# or
pip install "cryptobot-python[webhook]"

Install documentation tooling extras:

uv add "cryptobot-python[docs]"
# or
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:

Category Methods
App get_me()
Invoices create_invoice(...), get_invoices(...), delete_invoice(...)
Transfers transfer(...), get_transfers(...)
Checks create_check(...), get_checks(...), delete_check(...)
Balance & Rates get_balances(), get_exchange_rates(), get_currencies()
Statistics get_stats(...)
Pagination iter_invoice_pages(...), iter_invoices(...), iter_transfer_pages(...), iter_transfers(...), iter_check_pages(...), iter_checks(...)

AsyncCryptoBotClient provides the same methods with await, plus async iterators for all pagination helpers.

List methods like get_invoices(...), get_transfers(...), and get_checks(...) accept 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.

Transfer with idempotency

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)

Crypto checks

Create a check that any user (or a specific user) can activate:

from cryptobot.models import Asset

check = client.create_check(asset=Asset.USDT, amount=1.0)
print(check.check_id, check.bot_check_url)

# Pin a check to a specific user
check = client.create_check(asset=Asset.TON, amount=0.25, pin_to_user_id=123456789)

# List and delete checks
checks = client.get_checks(asset=Asset.USDT, status="active")
client.delete_check(check_id=checks[0].check_id)

App statistics

stats = client.get_stats(
    start_at="2026-01-01T00:00:00Z",
    end_at="2026-03-01T00:00:00Z",
)
print(stats.volume, stats.unique_users_count, stats.paid_invoice_count)

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.

About

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

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors