BitPay payment gateway integration for python-getpaid ecosystem.
Project description
getpaid-bitpay
BitPay payment gateway plugin for the
python-getpaid ecosystem. Provides a
fully async HTTP client (BitPayClient) and a payment processor
(BitPayProcessor) implementing the
getpaid-core
BaseProcessor interface. Communicates with BitPay via their REST API v2
using POS and merchant facade authentication.
Status: Alpha — under active development.
Architecture
getpaid-bitpay is composed of three layers:
- Signing — EC key (secp256k1) generation, compressed public key derivation, and ECDSA-SHA256 message signing used by the merchant facade.
- BitPayClient — a low-level async HTTP client (built on
httpx) that wraps the BitPay REST API v2 endpoints. Supports POS facade (token-only) and merchant facade (EC key signed requests). Can be used as an async context manager for connection reuse. - BitPayProcessor — a high-level processor that implements
BaseProcessorfrom getpaid-core. Translates between the core payment protocol and BitPay's API, handles IPN webhooks, PULL status polling, and FSM transitions.
Why not the official SDK?
This plugin uses its own native async HTTP client instead of wrapping the official BitPay Python SDK. The reasons:
- Sync-only — the official SDK uses
requests, requiring thread offloading for every call in an async context. - Pydantic version pinning — the SDK pins
pydantic==2.11.9exactly, causing dependency conflicts in projects using different Pydantic versions. - Testing opacity — mocking
requestsinside third-party code is fragile; withhttpxwe userespxfor clean, reliable test doubles. - Minimal surface — we only need invoices and refunds (6 endpoints), not the SDK's 40+ methods.
- Small footprint — the custom client is ~275 lines, a net reduction in complexity compared to wrapping the full SDK.
Key Features
- Invoice creation via POS facade (token-only authentication)
- Invoice retrieval, cancellation via merchant facade (EC key signing)
- Refund creation, retrieval, cancellation via merchant facade
- Callback authenticity verification via
X-SignatureHMAC - IPN webhook handling for both invoice and refund status changes
- PULL status polling via
fetch_payment_status - Two-step payment confirmation (confirm_payment + mark_as_paid)
- Automatic refund completion (confirm_refund + mark_as_refunded)
- Sandbox and production environment support
Quick Usage
BitPayClient can be used standalone as an async context manager:
from getpaid_bitpay.client import BitPayClient
async with BitPayClient(
base_url="https://test.bitpay.com",
pos_token="your-pos-token",
) as client:
invoice = await client.create_invoice(
price=29.99,
currency="USD",
order_id="order-123",
notification_url="https://example.com/webhooks/bitpay",
)
checkout_url = invoice["url"]
For merchant facade operations (invoice retrieval, refunds), provide an EC private key and merchant token:
from getpaid_bitpay.client import BitPayClient
from getpaid_bitpay.signing import generate_pem
# Generate a key pair (do this once, store the PEM securely)
private_key_pem = generate_pem()
async with BitPayClient(
base_url="https://test.bitpay.com",
pos_token="your-pos-token",
merchant_token="your-merchant-token",
private_key_pem=private_key_pem,
) as client:
invoice = await client.get_invoice("invoice-id-123")
refund = await client.create_refund(
invoice_id="invoice-id-123",
amount=10.0,
)
Key Generation
BitPay merchant facade requires an EC key pair (secp256k1). The signing module provides a helper:
from getpaid_bitpay.signing import generate_pem, get_compressed_public_key
# Generate a new private key in PEM format
pem = generate_pem()
# Derive the compressed public key (hex) — needed for BitPay dashboard pairing
public_key_hex = get_compressed_public_key(pem)
print(public_key_hex) # e.g. "02a1b2c3d4..."
Store the PEM string securely (e.g. in environment variables or a secrets manager). The compressed public key hex is used when pairing with the BitPay merchant dashboard to obtain your merchant token.
Configuration
When used via a framework adapter (e.g. django-getpaid, litestar-getpaid), configuration is provided as a dictionary:
| Key | Type | Required | Description |
|---|---|---|---|
pos_token |
str |
Yes | POS facade API token from BitPay dashboard |
merchant_token |
str |
No | Merchant facade API token (needed for refunds, invoice retrieval) |
private_key_pem |
str |
No | EC private key in PEM format (needed for merchant facade signing) |
sandbox |
bool |
No | Use sandbox (test.bitpay.com) or production (bitpay.com). Default: True |
notification_url |
str |
No | IPN webhook URL template, e.g. https://example.com/payments/{payment_id}/notify |
redirect_url |
str |
No | Redirect URL template after payment, e.g. https://example.com/payments/{payment_id}/done |
Example configuration dict:
GETPAID_BACKENDS = {
"bitpay": {
"pos_token": "your-pos-token",
"merchant_token": "your-merchant-token",
"private_key_pem": "-----BEGIN EC PRIVATE KEY-----\n...",
"sandbox": True,
"notification_url": "https://example.com/payments/{payment_id}/notify",
"redirect_url": "https://example.com/payments/{payment_id}/done",
}
}
Note:
merchant_tokenandprivate_key_pemare only required if you need merchant facade operations (invoice retrieval, cancellation, refunds). Basic invoice creation works with justpos_token.
Status Mapping
Invoice Statuses
| BitPay Status | FSM Trigger | Description |
|---|---|---|
new |
confirm_prepared |
Invoice created, awaiting payment |
paid |
confirm_payment |
Payment detected, awaiting confirmation |
confirmed |
mark_as_paid |
Payment confirmed on blockchain |
complete |
(none) | Invoice complete, no further action |
expired |
fail |
Invoice expired without payment |
invalid |
fail |
Payment invalid |
declined |
fail |
Payment declined |
Refund Statuses
| BitPay Status | FSM Trigger | Description |
|---|---|---|
pending |
(none) | Refund pending processing |
created |
(none) | Refund created |
preview |
(none) | Refund in preview |
success |
confirm_refund |
Refund completed successfully |
failure |
cancel_refund |
Refund failed |
cancelled |
cancel_refund |
Refund cancelled |
Supported Currencies
BTC, BCH, DOGE, ETH, LTC, MATIC, SHIB, USDC, USDP, BUSD, PAX, XRP, APE, EUR, GBP, USD, CAD, AUD
Requirements
- Python 3.12+
python-getpaid-core >= 0.1.0httpx >= 0.27.0ecdsa >= 0.19.0anyio >= 4.0
Related Projects
- getpaid-core — framework-agnostic payment processing library
- django-getpaid — Django framework adapter
- litestar-getpaid — Litestar framework adapter
License
MIT
Disclaimer
This project has nothing in common with the getpaid plone project.
Credits
Created by Dominik Kozaczko.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_getpaid_bitpay-0.1.1.tar.gz.
File metadata
- Download URL: python_getpaid_bitpay-0.1.1.tar.gz
- Upload date:
- Size: 59.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.3 {"installer":{"name":"uv","version":"0.10.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Manjaro Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21b666ba66421dbe9e2abc67de8560f7da38466f4c78c99c07116ab87b2c6268
|
|
| MD5 |
9f0e30c27e796af6b1898380872754be
|
|
| BLAKE2b-256 |
f3eb59a63bd51f77eb98de84071f11ca127b56018a39cd153d935d632cc7de82
|
File details
Details for the file python_getpaid_bitpay-0.1.1-py3-none-any.whl.
File metadata
- Download URL: python_getpaid_bitpay-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.3 {"installer":{"name":"uv","version":"0.10.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Manjaro Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b61dbe089ed8302468c4351f7d998408b594d6b6f60166f9e9390101d81951a3
|
|
| MD5 |
d4c7177062c75d18b0303514c8f575b2
|
|
| BLAKE2b-256 |
7dacb0259b02acf78b9c4c868253ad39f327c8833b4c14ae7802a1b78a2f25f8
|