Skip to main content

BitPay payment gateway integration for python-getpaid ecosystem.

Project description

getpaid-bitpay

PyPI Python Version License

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 BaseProcessor from 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:

  1. Sync-only — the official SDK uses requests, requiring thread offloading for every call in an async context.
  2. Pydantic version pinning — the SDK pins pydantic==2.11.9 exactly, causing dependency conflicts in projects using different Pydantic versions.
  3. Testing opacity — mocking requests inside third-party code is fragile; with httpx we use respx for clean, reliable test doubles.
  4. Minimal surface — we only need invoices and refunds (6 endpoints), not the SDK's 40+ methods.
  5. 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-Signature HMAC
  • 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_token and private_key_pem are only required if you need merchant facade operations (invoice retrieval, cancellation, refunds). Basic invoice creation works with just pos_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.0
  • httpx >= 0.27.0
  • ecdsa >= 0.19.0
  • anyio >= 4.0

Related Projects

License

MIT

Disclaimer

This project has nothing in common with the getpaid plone project.

Credits

Created by Dominik Kozaczko.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_getpaid_bitpay-0.1.1.tar.gz (59.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_getpaid_bitpay-0.1.1-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

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

Hashes for python_getpaid_bitpay-0.1.1.tar.gz
Algorithm Hash digest
SHA256 21b666ba66421dbe9e2abc67de8560f7da38466f4c78c99c07116ab87b2c6268
MD5 9f0e30c27e796af6b1898380872754be
BLAKE2b-256 f3eb59a63bd51f77eb98de84071f11ca127b56018a39cd153d935d632cc7de82

See more details on using hashes here.

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

Hashes for python_getpaid_bitpay-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b61dbe089ed8302468c4351f7d998408b594d6b6f60166f9e9390101d81951a3
MD5 d4c7177062c75d18b0303514c8f575b2
BLAKE2b-256 7dacb0259b02acf78b9c4c868253ad39f327c8833b4c14ae7802a1b78a2f25f8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page