Weird library that handles BTC, BCH, BSV, and XMR payments.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Teran McKinney 1749381a29 No longer maintained 4 months ago
bitcoinacceptor 0.10.0: Better XMR to fiat API handling, slight breaking change for probably unused function 7 months ago
tests 0.10.0: Better XMR to fiat API handling, slight breaking change for probably unused function 7 months ago
.flake8 0.8.0: Add final_cents, final_price, hit_floor returns 1 year ago
.gitignore mypy, some typing 8 months ago
LICENSE.txt Initial commit 5 years ago No longer maintained 4 months ago
mypy.ini 0.9.0: Replace namedtuple with dataclass, txid False changed to None 7 months ago
requirements.txt 0.2.4: Fix BCH 3 years ago 0.10.0: Better XMR to fiat API handling, slight breaking change for probably unused function 7 months ago 0.10.0: Better XMR to fiat API handling, slight breaking change for probably unused function 7 months ago

bitcoinacceptor: Accept Bitcoin, BitcoinCash, BitcoinSV, and Monero (no longer maintained)


  • pip3 install bitcoinacceptor


  • ./


Monero requires a RPC wallet to connect to.

import bitcoinacceptor
from time import sleep

# This is only important for roughly time_window / 2.
# Prevents double buys.
transactions = []

hath_spoken = False
while True:
    address = '16jCrzcXo2PxadrQiQwUgwrmEwDGQYBwZq'
    payment = bitcoinacceptor.payment(address=address, satoshis=10000, unique='random_uuid')
    if payment.txid is False:
        if hath_spoken is False:
            print('Send {} Satoshis to {}'.format(payment.satoshis, address))
            hath_spoken = True
        if payment.txid not in transactions:
            print("Here's the product.")

What it does

The text below may be out of date and unreliable. Read the code and decide if this is right for you. Even the code comments may not be correct.

tl;dr: This is really weird. But I think it works in the realm of single digit transaction per second workloads. It's not perfect and it's not totally safe for you or your users, but it may be good enough for most.

Lets you somewhat reliably accept payments to a single Bitcoin address without payment forwarding and what not.

It does this by using time windows and deterministic generation of the last X Satoshis for the payment. By default, it's 10,000 Satoshis in a 300 second window. This means that if you have an item that costs 20,000 Satoshi, the user price may vary from 20,000 to 30,000 Satoshi. When the library says the item is paid, you need to track state. This does not keep state for you. As soon as you get status True, log that somewhere, somehow. This also means that for Y products at the same price, the seconds is roughly your throughput before you start getting collisions.

Potentially, anyway. You'll want to use a high poll rate with this. Probably have the user hitting you every five seconds or sooner. There's attack windows of the poll time where an attacker can try to brute force the unique between payment and polling. If your unique (this is deterministic, afterall) is exposed (like unencrypted on the wire or public in some other way), consider salting it and not disclosing the salt.

You tell them to pay the same address that you pass to bitcoinacceptor.payment(), but be sure to give them payment.satoshis as the amount.

Your clock should be kept in sync. The default time_window of 300 seconds is probably a bit much, but it should work for most low traffic sites.

There's other attacks where someone can flood your account with Bitcoins and block out transactions that way. Using bitaps, that number seems to be 100, so it would have to be like 30 transactions per second before things started getting risky at a 2 second poll rate. If it were precisely 2 seconds, that is. Either way, it might be an expensive attack to pull off which might profit you more than your normal business, unless it iritated customers enough to not come back and the attacker/donator stopped.

You probably want to only use this with base Satoshis of 10,000 or more.

This is meant for 0 confirmation transactions at a moderate to low rate. For the impatient and not endlessly successful.

Thinking about this more, an attacker can hit your endpoint enough times to build a table of all possible prices. The attacker can then wait for payments and strike with pre-computed payloads. The first request to reach the endpoint wins, more or less. So if you are giving a digital product that you don't care much about, it's probably fine. If not, the user may lose out. EDIT: We now add time to the salt and check current salt and previous salt.

You'll want to log txids for time_window /2, roughly. If the txid has been used, don't do it again. That prevents the multiple buys per transaction attack.


0.1.0 is way different. It's Python 3 only. Uses bit. Default satoshi_security is 1,000 instead of 10,000.

Also, it uses confirmations instead of time. So someone can spam you with TXs that will never confirm and get free stuff.

Has this made you millions and you're feeling generous?

  • Bitcoin: 19PyKGyYBn5Xg5LmofyxEU1oy6rDgZ4yiS
  • Bitcoin Cash: qrs8spxa5eyvs7gsejaf0cv2dtt9l4czk5wznepfze
  • Bitcoin SV: 17RAeAnVdfTG4uEAnXKbPQ93pkg4jjaFKS
  • Monero: 42CDfnw6j2FgZYg5rAPMmWg73WdmLHbAaj1PQLtw2uuwZmT53gPddhEHQAgBKxSo1iYTaTRovmkn68r9rvGbgzPyBN5rohJ


Unlicense/Public domain