weeasycrypto (Python)
Official Python SDK for the WeEasyCrypto tenant API: deposit addresses, balances, deposits, withdrawals, and signed webhooks.
- One runtime dependency. HTTP via
urllib; Ed25519 (request signing and webhook verification) via the auditedcryptographypackage (the stdlib has none). A custom transport is injectable for proxies, test stubs, or record/replay. - Signing you never hand-write. Every request carries an Ed25519
signature (
X-Timestamp+X-Signature) computed over the exact bytes sent on the wire — the platform holds only your public key and can verify, never forge. Webhook deliveries are Ed25519-signed too (v1a, per-tenant platform key) — verified with your tenant's public key, ±300 s tolerance. - Amounts are decimal strings, never floats.
parse_amount/format_amountuse pure integer arithmetic.
⚠️ Server-side only. Your Ed25519
private_keymust never reach a browser or mobile bundle — it was generated locally when the key was issued and the platform cannot recover it.
Install
pip install weeasycrypto
Quickstart
import os
from weeasycrypto import WeEasyCrypto
cv = WeEasyCrypto(
base_url="https://api.example.com",
api_key=os.environ["WEEASYCRYPTO_API_KEY"], # keyId, e.g. "ck_…"
private_key=os.environ["WEEASYCRYPTO_PRIVATE_KEY"], # hex Ed25519 seed, generated at issuance
webhook_public_key=os.environ.get("WEEASYCRYPTO_WEBHOOK_PUBLIC_KEY"), # portal → Settings → Integrations
)
# Issue a deposit address
addr = cv.addresses.create(label="user-42", chain_key="tron")
addr.family # 'EVM' | 'TRON' | 'BTC' | 'SOL' | 'TON'
# Balances — amounts are decimal strings, never floats
balances = cv.balances.list()
# Deposits with auto-pagination
for d in cv.deposits.iterate(status="CONFIRMED"):
print(d.tx_hash, d.amount)
Withdrawals — the idempotency contract
request_id is your idempotency key. Persist it in your own database
before calling; the SDK deliberately never generates one, because a
regenerated key after a crash is how double-payouts happen.
from weeasycrypto import ConflictError
try:
w = cv.withdrawals.create(
request_id="wd-20260710-0001", # yours, persisted first
chain_key="eth-mainnet",
token_symbol="USDT",
to="0x…",
amount="100.5", # always a string
)
except ConflictError as err:
if err.is_duplicate_request:
# Safety signal, not a failure: an earlier attempt already created it.
# Look the withdrawal up via the id you stored against this request_id.
...
else:
raise
# Poll to a terminal status (webhooks are the push-based alternative)
final = cv.withdrawals.wait_until_final(w.id)
# final.status: 'CONFIRMED' | 'FAILED' | 'REJECTED' | 'CANCELED'
if final.status == "CONFIRMED":
print(final.tx_hash)
Network errors on withdrawals.create / create_batch are retried
automatically with the same request_id — that can never double-spend.
addresses.create has no idempotency key, so it is never auto-retried;
list() recent addresses before creating again if the outcome was unknown.
Webhooks
Deliveries carry X-Webhook-Signature: t={ts},v1a={hex} — an Ed25519
signature over {ts}.{body} made with a per-tenant platform key.
Verification needs only your tenant's public key (webhookSignPublicKey
in the merchant portal, Settings → Integrations); there is no shared
secret to protect.
# Flask example — raw body must be the exact bytes received.
from weeasycrypto import WebhookVerificationError
@app.post("/webhook")
def webhook():
try:
event = cv.webhooks.parse(
request.get_data(), request.headers.get("X-Webhook-Signature")
)
except WebhookVerificationError:
return "", 400
if event.type == "deposit.confirmed":
credit(event.data["depositId"], event.data["amount"])
elif event.type == "withdrawal.completed":
mark_paid(event.data["requestId"])
# New event types appear over time — ignore what you don't know.
return "", 200
Errors
WeEasyCryptoError
├─ APIError (status / code / request_id)
│ ├─ AuthenticationError(401) ├─ PermissionDeniedError(403)
│ ├─ NotFoundError(404) ├─ ConflictError(409) # .is_duplicate_request
│ ├─ ValidationError(422) └─ ServerError(5xx)
│ └─ RateLimitError(429) # .retry_after_ms
├─ NetworkError # no HTTP response; safe to replay withdrawals
├─ WebhookVerificationError
└─ TimeoutError # wait_until_final budget exceeded
Testing
python3 -m venv .venv && .venv/bin/pip install -e . pytest
.venv/bin/pytest
Signing is verified against the shared golden vectors in
../vectors/signing-vectors.json.
Metadata
Release files for weeasycrypto 0.2.0
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 | |
|---|---|---|---|---|
| weeasycrypto-0.2.0.tar.gz | 20.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| weeasycrypto-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 42.0 kB
Release files / weeasycrypto-0.2.0.tar.gz
| Download URL | weeasycrypto-0.2.0.tar.gz |
|---|---|
| Size | 20.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6a781399c341709d4323ff9858b4c6db8f349b0eec541e9366ca3ec5142429cc
|
|
BLAKE2b-256 checksum How to use checksums |
5227a1241a97fc12392a7b05a9d873c82273d9255d473a6660bdac9d411287db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / weeasycrypto-0.2.0-py3-none-any.whl
| Download URL | weeasycrypto-0.2.0-py3-none-any.whl |
|---|---|
| Size | 21.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fc00b9c9180c5c468ed9d9a8eca4e03dfb04d3c5cdb3a1df1417eeaef791dae4
|
|
BLAKE2b-256 checksum How to use checksums |
4a970f34e8b2f435f13999c03651a1015bd290613bac3592f0e750d148568426
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Security for weeasycrypto 0.2.0
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.