API payment protocol
This is a proposal for how automated payment for API usage of a service could be achieved using payment channels. ElectrumSV wants to do this to compensate people who will run the services our users make use of, but perhaps others might have an interest in also supporting it. Maybe to provide some of the services we need.
I am not a Bitcoin expert. This is also only intended to be approximately correct, as I do not have a lot of experience with payment channels, and I am not sure many others have either. Everything below this point is semi-educated hand-waving, perhaps the worst kind of hand-waving!
Our users may not know they are using your service.
Services should be used by the wallet and the user may not even know they are being used. If for every service an ElectrumSV user uses they need to sign up with it manually, and provide a credit card, this is prohibitive. ElectrumSV should be able to provide it’s basic functionality with zero configuration where possible, and just appear to work.
There may be APIs that require a manual credit card funding, perhaps because the user cannot be assumed to already have a wallet balance. An example of one, is the restoration API which will replace seed-based restoration in the longer term. Using an API to regain access to your BSV, in order to have BSV which you can pay people with, is a chicken and egg situation.
Let’s say we have an ElectrumSV user Alice, and she is using a hosted service which is perhaps providing her with some useful data she is blissfully unaware of. She has a petty cash balance in the wallet, which the wallet can use to operate services like this on her behalf without her permission. There are of course expectations on her part like not wanting to overpay for use of services, but she generally accepts there will be an ongoing cost in the form of micropayments or nanopayments.
The wallet knows that the services it uses have a standard API, and one of these is a service discovery endpoint. From this it identifies that it supports a useful endpoint it needs, it also identifies the pricing policy. For a data search/processing endpoint, this may be dependent on the CPU used and bandwidth consumed. For an endpoint which retains data on the user’s behalf this may indicate how much they need to pay to retain data until a given expiry date based on how much data they have stored. And there may even be one off cost endpoints, like reservation of a Paymail identity.
Unfunded anonymous access
Perhaps the wallet attempts to use an expected endpoint the service just happens to support, and has not engaged in service discovery to either find it and or gauge the cost. It gets back a 402 “payment required” response with attached metadata pointing to the service discovery endpoint.
The wallet invisibly creates an account with the service in a deterministic way where it can identify if it has an account in future without requiring a password. It gives a prefunding transaction to the service and gets back an API key.
The wallet should not lock up funds it cannot afford to lock up in that prefunding transaction, any UTXOs in it should start off with sequence number 0, and be considered allocated for future usage in this channel. If the wallet ever wants to free up the change, it should do so in a way that is compatible with the server, and this will involve broadcasting the latest version of the transaction. If it double spends the UTXO somewhere else, this is considered to be broken or malicious.
The wallet now makes requests with the API key. The service returns the charges for each request in the response headers, and the wallet should be able to use these to gauge the balance of the channel.
Either the wallet will proactively update the payment channel via the service’s funding endpoint before it is too empty, or it will eventually incur a 402 response for every subsequent request.
So let’s try to build a picture of how the channel is managed.
Finalising the payment channel
Either party may find themselves in a position where they want to broadcast the transaction. The wallet may want access to change. The service may want to commit the current balance.
One way they could discover that a version of the payment channel transaction has been broadcast, is by using the future UTXO spend notification mechanism which Steve Shadders showed as on the roadmap at CoinGeek NY 2021.
If the wallet detects the latest transaction is broadcast unexpectedly, this could reveal the service is stealing the wallet’s outstanding balance. The wallet however, is not guaranteed to be online all the time and may receive this notification in a peer channel when it was offline. It cannot be sure to respond in a timely fashion, and how it could respond is unclear. It does imply the best approach is to prepay conservatively, and why wouldn’t it.
If the service detects the latest transaction is broadcast unexpectedly, what does it do with any outstanding balance? A better approach to the wallet finalising the channel, would be to have an endpoint for that explicitly in the service where the wallet posts an updated version with the final agreed upon reduced balance going to the service and this is considered proper finalisation.
If the service detects an older version is broadcast where it gets less balance than the latest version, it considers this a fraudulent user and it broadcasts the latest version. And that user is blacklisted, their IP address and revealed details logged, and whatever else. The amount of funds at stake should be nominal and the service should get real time updates. There is even an argument of unknown benefit for an up sale service to this hosting service from another party, where the other party holds onto offchain transactions enters into a contract to only broadcast them at the appropriate time. For non-final transactions this might be when an outdated version is broadcast, to immediately overwrite them.
So in theory, the channel should be managed as such:
- The wallet creates a non-final prefunding transaction.
- The service runs a spent balance ideally less than or equal to the current prefunding.
- Each request from the wallet is accounted to the spent balance and a receipt returned in the response. If there are insufficient funds to complete the request, it may incur a 402 response or interrupt any streamed data.
- When the wallet wishes to finalise the prefunding transaction, it does so through an API on the hosting service.
- If the last prefunding transaction is finalised, the wallet needs to create a new one. This will ideally happen before the previous funding is completely spent to avoid 402 or more ambiguous interrupted responses.
More bits and pieces
If the Alice has backups on a hosting service and wants to have a minimum period of retention for the amount of data they have stored, she will probably want to have a guarantee of retention. She would likely not want the backup balance to be mixed with the general API usage balance. She needs to see that she has 3 months before she loses her backups, not to see it jump around. And she might want to know she can be away for 2.5 months, before she has to worry about adding more funding for the data retention. This suggests that either she might have to prepay for that data retention.
From ElectrumSV’s perspective we want programmatic API discovery and programmatic pricing discovery. If there are standard endpoints that are expected on a service’s API, of which only some might be supported, then we want to know which are supported. Rather than trying all the endpoints we are interested in, it is better to have a centralised API discovery endpoint.
Similarly, it is in the wallet’s interest if the service publishes a pricing policy perhaps with an expiration date, and every discoverable service is listed with the form of pricing that is involved.
The above is solid enough that we can take it and build it. But it is not yet implemented and it is only being thought out to prove ElectrumSV has a model that can work for now. We will likely polish this potential solution and see how well it works when we get our other ducks in a row and are ready to implement it.
The value in fleshing out this model now means that we have a starting point to use as a frame of reference. Others can also understand better what we are looking for, and can work out if they want to work with us to implement something like this.
If any others wish to work on fleshing out both the API service discovery model and the payment channel model, then please get in touch.