Recurr - Protocol for Recurring (Push) Payments

Hi all,

I’ve been working with @Leandrodimarco on a protocol/approach for Recurring (Push) Payment services.

In concept, it functions similar to an RSS feed - the Recurr application itself is an “aggregator” that would allow users to add Recurr-formatted feeds from service providers (that support it) and view/instantiate the payment of bills from within the app.

Although this is not necessarily BCH specific (it uses URL’s to instantiate actions like payments - meaning most payment methods/gateways could be supported), we’d like to reach out to the BCH community for feedback on the specification/approach - as BCH was the primary motivation for this project.

The website with more detail and a (WIP) MVP WebApp can be found here:
https://recurr.app/
(Examples feeds should also work if anyone would like to see how it would function.)

The design goals for this are primarily:

  1. To be simple for services to implement (NodeJS example of how implementation may look is around 100 lines: Guide - Recurr).
  2. To allow both fiat and crypto bill payments.
  3. To be decentralized in the sense that the protocol does not depend upon any central server to function (avoids contention).

The main item of concern we have is enhancing security - in a way that does not over-complicate the implementation for services (or make implementation too difficult):
Currently, if a Feed URL is exposed, a user’s bills/receipts (fee payload) would also be exposed. Although HTTPS will be mandated (thereby obscuring URL paths from any MITM), these URL’s would still appear in server-logs, etc.
Hoping to feel the waters for what could possibly be done to enhance this while making it so implementation for services is still simple/easy. Currently, implementation should be able to be done in around 100-150 lines of code. Guide here demonstrates how it might look in < 100 lines: Guide - Recurr
The current approach we’re considering to enhance security is using a symmetric key which is included in the scan URL and having the service then encrypt the feed payload with this key (ideally, with an encryption algorithm that’s well supported across languages). We’re open to using a Private/Public keypair also - but are concerned that it might complicate implementation. Opinions on this would be much appreciated.

We do also plan to support Push Notifications (as opposed to only RSS-like polling) - but that will likely be in a future version of the spec and will not force the use of any particular Push Notification service so that we can maintain a decentralization and avoid contention. As it is currently, the protocol supports “delta” records and that, combined with a compression (gzip is supported by all major HTTP servers), means the payload remains small. Hence, even as is, bandwidth usage should be fairly minimal.

We also plan to create Native Apps for iOS/Android as Progressive Web Apps (PWA) have some limitations - however, we would like to finalize the proto and PWA before focusing on these pieces.

Any other feedback/recommendations/thoughts would be much appreciated.

Thanks all!

4 Likes

So basically the user provides a content creator with a key that’s good for a recurring and limited IOU to a certain amount that charges to a wallet app automatically, which can be set up with any private key? Then the content creator sends out the RSS post key every month (or whatever time period)?

Edit (performed and completed seconds before a reply): I guess hypothetically it’d work with regular subscription, content creators posting their wallet address basically, and users setting their own recurring amount to send to requests/wallet addresses that appear in the feed. Whatever wallet software is used should keep track of maximum times to send. Although this same behavior could just be accomplished with a literal non-updated/offline list of wallet addresses

I think this kind of features is very very important to get working for smooth UX. Without checking the details I wonder if you have considered the same functionality but as extension(s) to BIP-70 instead? Those wallets that supports it already has, for instance, protobuf support and can verify x509 signature chains which could very well be leveraged here.

Not quite - the design is inspired by RSS, but it’s not actually using RSS proto. It’s using a custom JSON format tailored specifically for billing. Think of it more as a notification system for when bills are due. And when you receive a new bill, you click/tap it and a list of payment methods are shown. The actual payments themselves are not automatic.

Best way to explain is probably through demonstration:
https://recurr.app/
There’s a few demos on the site where the QR codes are (bottom right on Desktop). If you click the “Open in WebApp” link below them, the feed for the demo service will be added to the App and you can click on one of the bills to get a feel for how it would work.

1 Like

With this, it’s not actually BCH specific (that’s just the motivation for the project). One of the design goals is also to support fiat (so that services that only support ‘push’ fiat payments currently can later support BCH). So we didn’t want to make this a BCH-only specification by doing something like amending the BIP70 spec (which is crypto-specific) as we wanted it to be a “bridge” of sorts.

That said, the demos on the site (QR Codes bottom right on desktop) are using BIP70 to process the payment. Feel free to try it out - should work (the actual amount it’ll send should be ~$0.05USD and the bill should disappear from the app after payment and land under receipts).
https://recurr.app/

Feel free to try the Stripe Payment as well if you’re not comfortable paying BCH. Stripe provides a test credit card number:
4242 4242 4242 4242
(Just put in any random details for Name, etc, and it should work)

As a service I’d be fine if Recurr compatibility was literally in my wallet apps, and there was an option to “send to all” and also “autopay on connect” for any bills or particular ones. There could also be “autopay max” per “time period” for particular ones as well.

Since the companies are setting the fees, that sort of feature for more automation is needed.

I see the issue though with the idea, since wallets would have to have local offline files stored with that information unless it’s a trusted wallet host/ing server.

For any recurring payment system today with modern content creation and monetization, “budget and forget” is how people make money. Seeing a bill that’s due is not ‘set it and forget it’ for smaller hosts. Perhaps I need to make a BCH-‘eon’ before anyone else for this Recurr app, where you’d host content creators and peoples’ wallets would only show it as paying you specifically. I know I don’t want to handle the recurring payments I do every month manually.

I would like to work out some scheme to allow the bills to automatically pay (perhaps by invoking the native wallet). It is a bit difficult from a security perspective though.

From a UX perspective, it’d be really neat to be able to select a “Pay Automatically” checkbox on a given payment option for a given service that invokes the user’s native wallet app (invisibly) to make the payment.

But, a malicious (or hacked) service could also exploit this by creating a very large bill (or several smaller bills amounting to a large sum) to essentially steal the user’s money.

Because amounts and frequencies of bills may vary, I haven’t really thought of a neat way of achieving this without tweaky logic (threshold percentage of expected amont/bill frequency). Am open to suggestions on this front.

Preferably though, although I’m not against Recurr being integrated into wallets, I’d like to avoid this for now as:

  1. The Protocol is intended to also be able to support fiat (with the hopes that these services will find it easy to support BCH/Crypto later).
  2. It’s a lot of additional work for BCH Wallet devs to implement properly (and we’d need to mitigate the security problem above)

Reading the docs I think I understand more about how this protocol is meant to work.
One thing I can say directly is that the URL is not in any way a sufficient secret to keep personal transaction history safe. Some kind of username/password authentication between the client and feed provider is needed and HTTP basic authentication headers is the very least to protect the data.

Another thing that I would like is that the bill URL, at least for BCH, should point directly to a BIP-70 URI so a payment could be done directly from a wallet subscribing to the feed without needing to open a webpage.

I’ll probably give some more feedback later.

Edit: Related to the point above with the URI. I think there should be some key/value field in each action inside the bills array specifying currency/protocol. If a specific wallet reads the feed it should be able to detect which payment method it could use itself and possibly provide a link/further info for the other options. For instance, one wallet that only understands BCH using BIP-70 should disregard every other action and another one that only understands BTC using jsonPaymentProtocol should use only that.

Currently it seems like the only way is to either parse the title string (which isn’t standardized) or follow the URL and figure stuff out from there.

For this, we’ll be looking at either the option of server encrypting the payload or some time-based signature mechanism with a key provided in the initial scan URL (e.g. recurr:api.recurr.app/feeds/internet/a951915d805c3#secret=asdfasdfasdf). We’d like to make sure whatever we use is well supported across languages though so it doesn’t complicate implementation. Personally, I’m leaning towards encrypted payload.

Technically, this is possible. For this demo, I haven’t done this though as: 1) BIP70 invoices have expiration time (could be solved by creating an invoice on-the-fly when URL loaded) and 2) This wouldn’t work with existing services like BitPay which require on page.

This isn’t a bad idea. My original hesitation with doing something like this is related to the above - many (most?) payment gateways like Bitpay (or existing services) rely on user landing on a page first and then selecting the currency that the user wishes to pay with. Hence, one payment option in Recurr might support several currencies. This probably could be done with an array of currency codes supported per Payment Option though. E.g. If a service is using Bitpay, a currencies field could be provided with values [‘BCH’, ‘BTC’, ‘ETH’].

In case of encrypted payload, how do the client get the decryption key?
In case of providing a secret in the initial scan, how can the key be rotated? I.e: what happens if a user changes to a new wallet/Recurr app. Does he/she need to export/import the secret or can a new secret be setup for a specific feed?

Note that if the feed is available for everyone in an encrypted form it will still leak some information, most specifically the size of the feed which could be analyzed to hint at how much activity a user has.

You would have to create the invoice on-the-fly anyway since the amount of BCH would vary due to price volatility. An invoice for $100 might be 0.1 BCH today, but 0.12 BCH or 0.8 BCH tomorrow.

I think we have some different views on what problem this protocol should solve. I was envisioning a protocol that would be able to replace a payment gateways landing page and let the wallet choose the appropriate method of payment. Your protocol seems more focused on the bills themselves and I’m interested more in the payments of them. Who do you see as the intended provider of the feeds? A service provider (like Netflix, power company or a telco) or a payment provider (like BitPay, Stripe or someone with crypto+creditcard)? I assume you see the former but I’m interested in a protocol for the latter.
Thus I will wish you good luck and refrain from further comments, unless I’m explicitly asked about something :slight_smile:

I had some early sketches of an overlay protocol for BIP-70 that would attempt to solve the problem I’m interested in but I haven’t made a real effort (as you have, kudos!) since I felt it was too ambitious and payment protocols in general are sadly quite shunned in other cryptocurrency communities.

The same key would work across clients. There’s actually import/export functionality available in the current (PoC) PWA Client. It just exports an array of the initial scan URLs. There’s no key-rotation built in. In “best practices” though, we will advise having a “revoke token” action in the event of compromise.
Theoretically, a service could also allow multiple tokens for the same feed.

I’m not sure this would be a big problem as the URL should not contain anything that’s PII. Also, HTTPS is going to be mandated so the token (URL path) should not be able to be sniffed through MITM (HTTPS encrypts URL paths). However, there is possibility of exposure of path in HTTP logs. This is why we’d like the additional layer of security (encryption or a time-based signature).

One concern here that you’ve made me think about re: encryption is that it makes the Gzip compression ineffective. This doesn’t matter so much if a service uses “Push Notifications” (which we hope to support in future), but for the current “polling” setup, it would considerably increase bandwidth. I’ll have to think about this one.

Services should create the feeds in most cases - not Payment Processors (though I’m operating under the principle here that “sometimes the best use cases are not those that you explicitly design for”). However, the intention is to make this relatively robust so that it can be integrated into existing services without too much effort.

To give an example of how this would work, Pornhub is probably a reasonable example.

  1. User creates account/logs in
  2. A Recurr QR Code is presented for that user (recurr://pornhub.com/recurr/a951915d805c3)
  3. Each month (or whatever Pornhub’s bill frequency is) a new bill is added to the Recurr feed.
  4. User selects a payment option (which is, ultimately, just a URI).

Depending on Pornhub’s implementation, if a user selects BCH, the URI might be a BIP70 payment URL. Or it could be a page that presents a BIP70 QR Code, etc. In short, the “smoothness” for a given payment option is determined by the service itself. The idea here is that some Recurr implementations may not be great to start with, but can be incrementally improved (e.g. direct BIP70 Payment URI) if it gains adoption/services are willing to put in the effort. Gradual adoption/improvement.

The URI approach also means that services that use push-payments currently - and notify users by email - should be able to implement this without fundamental changes to their payment infra. The link that would’ve been contained in the email can just be placed as the URI in the Recurr Payment Option.

For other services currently supporting BCH that use a “top-up” mechanism (e.g. Namecheap and Vultr), they could generate a Recurr feed per user that uses the “balances” object - and provide a URI link to their existing “deposit bch” pages - also without fundamental changes to payment infra.

I have someone working on a project to leverage Recurr at the moment - as I think this will better demonstrate how a “good” implementation would work in practice.

I understand this isn’t a perfect solution as it cannot emulate pull functionality. But, I’m hoping it does provide at least a mechanism for supporting recurring payments until someone designs something more elegant.

This is an important feature.