As part of supporting donation (and purchase) for apps in Flathub, each app (and platform) needs to be able to set their minimum and recommended values, and the cut given to their dependencies.
This document is intended to lay out how this might work, along with a proposed algorithm to turn a "pay X to app Y" into a transaction which divides the funds appropriately.
Each of Flathub, the platform(s) for the app, and the app, will be given the "token" amount regardless of any additional funds. For the purpose of this document we will consider the "token" amount 1 dollar.
Applications are permitted to receive donations, or to expect payment in return for being permitted to download the application.
Applications which expect payment may also define a recommended donation amount which is higher than the payment amount, though the user is under no obligation to pay that.
(Database, with APIs to manipulate)
- ID
- Application (String, FH appid)
- PaymentAmount
- DonationAmount
- PlatformCut
(JSON documents)
- Platform ID (e.g. org.freedesktop.Runtime)
- Dependency IDs (e.g. org.flathub.FlatHub)
- DependencyCut
GIMP is a free software project, they want to permit donations. They have a runtime of org.gnome.Platform and they set their platform cut at 50%
GNOME's platform builds atop FDSDK, so their platform definition includes FDSDK as a dependency. GNOME set the platform cut at 30%
FDSDK, as a basis platform for flatpak, depends on only FlatHub itself. FDSDK set the platform cut at 50%
GIMP's minimum "token" total is therefore 4 dollars (FH, FDSDK, GNOME, GIMP).
GIMP set their recommended donation level at 10 dollars.
A user clicks to donate to GIMP, they are presented with a dialog which shows the breakdown. This is computed as:
- Each party takes their token amount
- There are 6 dollars left
- GIMP takes its cut
- There are 3 dollars left
- GNOME takes its cut
- There are 90 cents left
- FDSDK takes its cut
- There are 27 cents left
- FlatHub takes the rest
Giving a final breakdown of:
- GIMP receives 4 dollars
- GNOME receives 3.10 dollars
- FDSDK receives 1.63 dollars
- FlatHub receives 1.27 dollars
The user is then permitted to shift the donation down to 4 or up to whatever they want, and the computation is rerun at whatever donation level they choose.
Game, by Publisher, is a pay-for game which the user will need to pay for before they can download and run it. The publisher sets the purchase price for the game at 15 dollars. The game uses the Freedesktop SDK as its platform. They set the platform cut at 30%.
A user clicks to buy Game, they are presented with a dialog showing the breakdown computed like before, giving:
- Game receives 9.40 dollars
- FDSDK receives 3.52 dollars
- Flathub receives 2.08 dollars
Again, the user can shift the amount but not below the purchase price of 15 dollars.
An app can set a recommended donation amount as per the GIMP example, and also a purchase amount as per the Game example, but if they do:
- Purchase amount must be less than or equal to recommended donation amount
- User will be presented with the slider at the recommended amount, but will be permitted to drop it as low as the purchase amount.
Returns the vending status for the given app ID. The app ID can be a platform
ID in which case the info will be returned for the platform. This permits
requesting the info for org.freedesktop.Runtime
or for org.flathub.FlatHub
for example.
If the given appid is not known, or any other error occurs, you will get a JSON object of the form:
{
"status": "error",
"error": "...",
}
If the appid is known, is permitted to receive donations / take payment, etc. then the returned data will be a JSON object of the form (using GIMP example):
{
"status": "ok",
"kind": "donation",
"components": [
"org.gimp.GIMP",
"org.gnome.Platform",
"org.freedesktop.Runtime",
"org.flathub.FlatHub",
],
"currency": "usd",
"tokens": [
100,
100,
100,
100,
],
"cuts": [
"50",
"70",
"70",
],
"minimum": 0,
"recommended": 600,
}
The intention is that the website can use the token values and cuts to render the UI properly, the minimum must be summed with the token values, and the recommended must be summed to the computed minimum. So in the above example, GIMP don't set a minimum above token (not a payment app) so 0 becomes 400 for the token values. Recommended becomes 1000 by adding to minimum.
Note that the cuts list will be one shorter than the components list because FlatHub always consumes the remaining amount, so it would be a redundant 100.
By comparison, this is what the Game example would return:
{
"status": "ok",
"kind": "purchase",
"components": [
"com.publisher.Game",
"org.freedesktop.Runtime",
"org.flathub.FlatHub",
],
"currency": "usd",
"tokens": [
100,
100,
100,
],
"cuts": [
70,
80
],
"minimum": 1200,
"recommended": 0,
}
In this Game example, there are three components, the game takes 70% of the non-token amount, (30% platform cut) but sets the purchase price at 15 dollars hence "minimum" is 1200 (plus the three token amounts becomes 1500). Because this is a pay-for game, and the publisher is not also doing free software, they set the recommended at zero, so the user will be presented with a dialog offering the total of 15 dollars.
If the publisher were also doing free software, they may choose to have a recommended donation value above the purchase price in which case that would be in the JSON returned.
This endpoint simply gives the split for the given app as the POST
endpoint
below would. If there is an error it'll be returned in the usual way, successful
currency splits would be given as:
{
"status": "ok",
"currency": "usd",
"split": {
"org.gimp.GIMP": 400,
"org.gnome.Platform": 310,
"org.freedesktop.Platform": 163,
"org.flathub.Flathub": 127,
}
}
It is up to the UI to order the split according to the components list and render things appropriately.
This endpoint creates a transaction to buy/donate to {appid}
. As before,
this might be an app in the appstream, or a platform ID.
The POST body must be JSON of the form:
{
"currency": "usd",
"amount": 1500,
}
If, in the future, we support currency conversions, this will allow users to donate/make payment in their own currency instead of dollars, but for now we're locking everything to dollars.
If the amount is less than the app's computed minimum value, then it will fail:
{
"status": "error",
"error": "amount_too_small",
}
Exact error message may vary, and other errors (e.g. database etc) may result in an error too.
If the amount is good, then a transaction of the right shape (as per the algorithm described above) is constructed and then returned as:
{
"status": "ok",
"transaction": "txnid",
}
Should we limit which apps can set a donation amount above the purchase amount? perhaps if the project license is not free software?
I assume the platform fees here are just an example. For the GIMP example the total platform fee is effectively 60%, which seems high. Apples take of 30% is already seen as high by the industry. Consider that too high of a fee may incentivise publishers to simply add dependencies to their own manifest. Perhaps the % donated to runtimes could be set by the app publisher instead.