Skip to main content

cryptunnel

Test PyPI Python License: MIT

Python SDK for Cryptunnel - accept crypto payments straight into your own wallets. Async-first for bots on aiogram, with a blocking mirror for scripts.

pip install cryptunnel

httpx is the only dependency. Python 3.10+.

Create a sandbox payment

from cryptunnel import CryptunnelSync

cryptunnel = CryptunnelSync("<merchant id>", "<api key>", sandbox=True)

print(cryptunnel.get_merchant())  # your credentials work if this prints your merchant

payment = cryptunnel.create_widget_payment(
    amount=10,
    currency="USD",
    external_id="order-1",
    success_url="https://example.com/thanks",
)
print(payment["url"])  # send the buyer here

sandbox=True sets is_test on every payment it creates: the payer is offered testnet currencies only, and the payment is excluded from your stats and fees. It is the same host and the same key - the sandbox is a flag, not a second account.

Verify a webhook

from flask import Flask, request

from cryptunnel import verify_webhook

app = Flask(__name__)
WEBHOOK_SECRET = "<whsec_...>"

@app.post("/cryptunnel")
def callback():
    if not verify_webhook(WEBHOOK_SECRET, request.headers, request.get_data()):
        return "", 401
    payment = request.get_json()
    if payment["status"] in ("confirmed", "confirmed_manual"):
        deliver(payment["external_id"])  # deduplicate on (id, status): retries repeat the same pair
    return "", 200

Pass the raw body bytes as received - parsing and re-serialising the JSON changes the signature. A failed delivery is retried 60 times, once a minute, for one hour, each attempt re-signed with a fresh timestamp over the same body.

Async

import asyncio

from cryptunnel import Cryptunnel

async def main():
    async with Cryptunnel("<merchant id>", "<api key>", sandbox=True) as cryptunnel:
        currencies = await cryptunnel.list_currencies()
        payment = await cryptunnel.create_h2h_payment(10, "USD", "order-2", currencies[0]["code"])
        print(payment["wallet_address"], payment["amount"], payment["currency"])

asyncio.run(main())

The whole surface

Method Call
create_widget_payment(amount, currency, external_id, ...) POST /v1/payments/widget
create_h2h_payment(amount, currency, external_id, target_currency, ...) POST /v1/payments/h2h
get_payment(payment_id) GET /v1/payments/{id}
list_payments(limit, offset) GET /v1/payments
list_currencies() GET /v1/currencies
get_merchant() GET /v1/merchants
verify_webhook(secret, headers, raw_body) local, no request
wait_for_payment(payment_id) polls GET /v1/payments/{id}

Every method exists on both Cryptunnel (await it) and CryptunnelSync (call it).

Payment creation is idempotent on external_id: a retry after a network timeout returns the payment you already created instead of a second one. Repeating an external_id with a different amount or currency is rejected with PAYMENT_ALREADY_EXISTS.

get_payment returns two shapes, and the status tells them apart: a created or expired payment carries no amount, currency or wallet_address, because nobody has picked a currency for it yet. Read them with payment.get("amount") rather than payment["amount"] unless you already know the status.

wait_for_payment is for scripts and development - it polls every 5 seconds, backing off to 30, and raises PaymentTimeoutError after 30 minutes. In production the webhook is the guarantee: a buyer who closes the page still produces a callback.

Errors

from cryptunnel import AuthenticationError, RateLimitError, ValidationError

try:
    cryptunnel.create_h2h_payment(10, "USD", "order-3", "DOGE")
except ValidationError as error:
    print(error.code)  # WALLET_NOT_FOUND - you have no active DOGE wallet
except AuthenticationError:
    print("check the merchant id and the api key")
except RateLimitError as error:
    print(error.retry_after)  # seconds to wait; None when the API sends no Retry-After header

CryptunnelError is the base; AuthenticationError (401), NotFoundError (404), ValidationError (400), RateLimitError (429) and ApiError (5xx and transport failures) derive from it. The raw API code is always on the exception.

MIT licensed.

Metadata

Release files for cryptunnel 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cryptunnel 1.1.0
File Size Uploaded
cryptunnel-1.1.0.tar.gz 10.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cryptunnel 1.1.0
File Interpreter ABI Platform
cryptunnel-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 20.3 kB

Release files / cryptunnel-1.1.0.tar.gz

Download URL cryptunnel-1.1.0.tar.gz
Size 10.5 kB
Tags Source
SHA-256 checksum
How to use checksums
bf789c06cd086a540e0ae7461366faa1f056c3331b0bc2ceabec53518e95ef4c
BLAKE2b-256 checksum
How to use checksums
b98fdc5faa93249537c85cf11eb7d59c45e56bbef8e34ed6f62dbaf133b1fc1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release files / cryptunnel-1.1.0-py3-none-any.whl

Download URL cryptunnel-1.1.0-py3-none-any.whl
Size 9.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f11a85bdf1533b80440f70acf40a6740a26ca0ab3d704ca06580c2f792b34877
BLAKE2b-256 checksum
How to use checksums
5c74ab8037e9e36f9153911bdb02f9578c966d833d12d629b679f1af6c0e507b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page