kopia lustrzana https://github.com/Podcastindex-org/podcast-namespace
319 wiersze
13 KiB
Markdown
319 wiersze
13 KiB
Markdown
# The "podcast:value" Specification
|
|
|
|
<small>Version 1.3 by Dave Jones - 2021.02.25</small>
|
|
|
|
<br>
|
|
|
|
## Purpose
|
|
|
|
Here we describe an additional "block" of XML that gives podcasters (and other media creators) a way to receive direct
|
|
payments from their audience in response to the action of viewing or listening to a created work. Utilizing so called "Layer 2"
|
|
crypto-currency networks like Lightning, and possibly other digital currency mechanisms, near real-time micropayments can
|
|
be directly sent from listener or viewer to the creator without the need for a payment processor or other "middle men".
|
|
|
|
The value block designates single or multiple destinations for these micro-payments. The idea is that the creator of the media
|
|
describes (within the feed) where and how they would like payments to be sent back to them during consumption
|
|
of that media. The format is designed to be flexible enough to handle many scenarios of direct payment streaming. Even
|
|
the use of fiat currency, if there is an API that is capable of interfacing as a receiver within this format.
|
|
|
|
<br>
|
|
|
|
## Play to Pay
|
|
|
|
This system can be thought of as Play-to-pay, rather than the traditional Pay-to-play paywall approach. When a
|
|
media listener (such as within a podcast app) presses the play button on an episode who's feed contains a value
|
|
block, a compatible app will be expected to begin streaming micro-payments to the designated recipients on a time
|
|
interval that makes sense for the app. The amount of each payment can be any amount the listener chooses, including
|
|
zero. If the listener chooses not to pay to listen to this media, then the app can ignore the value block of that feed.
|
|
|
|
<br>
|
|
|
|
## Payment Intervals
|
|
|
|
The "time interval" for calculating payments is **always 1 minute**. However, the actual interval between when payments
|
|
are sent can be longer. The interval should be chosen with a few factors in mind such as connectivity (is the app
|
|
currently on-line?), transaction fees (batch payments together to reduce fee percentage), cryptocurrency network load
|
|
(can the given crypto network or API support this payment rate?).
|
|
|
|
No matter what the chosen time interval for the actual transaction, the calculation should be done on a once-per-minute
|
|
basis. So, if the micro-payment is sent every 15 minutes, it should be calculated as 15 payments batched together
|
|
in a single transaction. Likewise, some apps with limited connectivity may need to only send payments once per
|
|
hour. In that scenario, there would be 60 payments added up into a single, larger payment. Batching transactions
|
|
like this also helps to minimize the impact of transaction fees on the underlying cryptocurrency network.
|
|
|
|
<div class="page"/>
|
|
|
|
<br><br>
|
|
|
|
## Elements
|
|
|
|
There are two elements that make up what we refer to as the "value block". They are a parent element that specifies the
|
|
currency to use, and one or more child elements that specify who to pay using the currency and protocol described by the
|
|
parent.
|
|
|
|
<br>
|
|
|
|
### Value Element
|
|
|
|
The `<podcast:value>` tag designates the cryptocurrency or payment layer that will be used, the transport method for transacting
|
|
the payments, and a suggested amount denominated in the given cryptocurrency.
|
|
|
|
This element can exist at either the `<channel>` or `<item>` level.
|
|
|
|
Currently, there can be only a single copy of this element at each level.
|
|
|
|
<br>
|
|
|
|
#### Structure:
|
|
```
|
|
<podcast:value
|
|
type="[cryptocurrency or layer(string)]"
|
|
method="[payment transport(string)]"
|
|
suggested="[payment amount(float)]"
|
|
>
|
|
[one or more "podcast:valueRecipient" elements]
|
|
</podcast:value>
|
|
```
|
|
<br>
|
|
|
|
#### Attributes:
|
|
- `type` (required) This is the service slug of the cryptocurrency or protocol layer.
|
|
- `method` (required) This is the transport mechanism that will be used.
|
|
- `suggested` (optional) This is an optional suggestion on how much cryptocurrency to send with each payment.
|
|
|
|
<br>
|
|
|
|
#### Explanation:
|
|
|
|
Using Lightning as an example, the `type` would be "lightning". Various possible `type` values will be kept
|
|
in a slug list [here](valueslugs.txt). This is the only type currently in active use. Others are under development
|
|
and will be added to the list as they see some measure of adoption, or at least a working example to prove viability.
|
|
|
|
The `method` attribute is used to indicate a sub-protocol to use within the given `type`. Again, returning to
|
|
Lightning as an example, the `method` would be "keysend". Normally, a Lightning payment requires an invoice
|
|
to be generated by the payee in order to fulfill a transaction. The "keysend" protocol of Lightning allows payments
|
|
to be streamed to what is, essentially, an open invoice. Other cryptocurrencies may have a similar protocol that
|
|
would be used here. If not, a value of "default" should be given.
|
|
|
|
The "suggested" amount is just that. It's a suggestion, and must be changeable by the user to another value, or
|
|
to zero. The suggested amount should always be given in the smallest denomination available within the payment
|
|
protocol being used. For instance, with Lightning it is given in millisatoshis.
|
|
|
|
A single value tag can contain many `<podcast:valueRecipient>` tags as children. All of these given recipients are
|
|
sent individual payments when the payment interval triggers.
|
|
|
|
The value tag, when it exists at the `<channel>` level, designates the payment scheme for the entire podcast. When it
|
|
exists at the `<item>` level, it is intended to override the channel level tag for that episode only.
|
|
|
|
#### Example:
|
|
|
|
```
|
|
<podcast:value
|
|
type="lightning"
|
|
method="keysend"
|
|
suggested="0.00000005000"
|
|
></podcast:value>
|
|
```
|
|
|
|
<br><br>
|
|
|
|
<div class="page"/>
|
|
|
|
### Value Recipient Element
|
|
|
|
The `valueRecipient` tag designates various destinations for payments to be sent to during consumption of the enclosed
|
|
media. Each recipient is considered to receive a "split" of the total payment according to the number of shares given
|
|
in the `split` attribute.
|
|
|
|
This element may only exist within a parent `<podcast:value>` element.
|
|
|
|
There is no limit on how many `valueRecipient` elements can be present in a given `<podcast:value>` element.
|
|
|
|
<br>
|
|
|
|
#### Structure:
|
|
|
|
```
|
|
<podcast:valueRecipient
|
|
name="[name of recipient(string)]"
|
|
type="[address type(string)]"
|
|
address="[the receiving address(string)]"
|
|
customKey="[optional key to pass(mixed)]"
|
|
customValue="[optional value to pass(mixed)]"
|
|
split="[share count(int)]"
|
|
/>
|
|
```
|
|
|
|
<br>
|
|
|
|
#### Attributes:
|
|
|
|
- `name` (recommended) A free-form string that designates who or what this recipient is.
|
|
- `customKey` (optional) The name of a custom record key to send along with the payment.
|
|
- `customValue` (optional) A custom value to pass along with the payment. This is considered the value that belongs to the `customKey`.
|
|
- `type` (required) A slug that represents the type of receiving address that will receive the payment.
|
|
- `address` (required) This denotes the receiving address of the payee.
|
|
- `split` (required) The number of shares of the payment this recipient will receive.
|
|
|
|
<br>
|
|
|
|
#### Explanation:
|
|
|
|
The `name` is just a human readable description of who or what this payment destination is. This could be something simple like
|
|
"Podcaster", "Co-host" or "Producer". It could also be more descriptive like "Ronald McDonald House Charity", if a podcaster
|
|
chooses to donate a percentage of their incoming funds to a charity.
|
|
|
|
The `type` denotes what type of receiving entity this is. For instance, with lightning this would typically be "node". This would
|
|
indicate that the `address` attribute for this recipient is a Lightning node that is capable of directly receiving incoming keysend payments. Valid values for
|
|
the `type` attribute are kept in the accompanying file [here](valueslugs.txt). Another option is given in examples below.
|
|
|
|
Payments must be sent to a valid destination which is given in the `address` attribute. This address format will vary depending on
|
|
the underlying currency being used.
|
|
|
|
The `split` attribute denotes an amount of "shares" of the total payment that the recipient will receive when each timed payment is made.
|
|
When a single `<podcast:valueRecipient>` is present, it should be assumed that the `split` for that recipient is 100%, and the "split" should
|
|
be ignored. When multiple recipients are present, a share calculation (see below) should be made to determine how much to send to each recipient's address.
|
|
|
|
<br><br>
|
|
|
|
<div class="page"/>
|
|
|
|
### Payment calculation
|
|
|
|
The interval payment calculation is:
|
|
|
|
(Number of shares / Share total) * Interval payout * Interval count
|
|
|
|
To calculate payouts, let's take the following value block as an example:
|
|
|
|
```
|
|
<podcast:value type="lightning" method="keysend" suggested="0.00000015000">
|
|
<podcast:valueRecipient
|
|
name="Host"
|
|
type="node"
|
|
address="02d5c1bf8b940dc9cadca86d1b0a3c37fbe39cee4c7e839e33bef9174531d27f52"
|
|
split="50"
|
|
/>
|
|
<podcast:valueRecipient
|
|
name="Co-Host"
|
|
type="node"
|
|
address="032f4ffbbafffbe51726ad3c164a3d0d37ec27bc67b29a159b0f49ae8ac21b8508"
|
|
split="40"
|
|
/>
|
|
<podcast:valueRecipient
|
|
name="Producer"
|
|
type="node"
|
|
address="03ae9f91a0cb8ff43840e3c322c4c61f019d8c1c3cea15a25cfc425ac605e61a4a"
|
|
split="10"
|
|
/>
|
|
</podcast:value>
|
|
```
|
|
|
|
This block designates three payment recipients. On each timed payment interval, the total payment will be split into 3 smaller
|
|
payments according to the shares listed in the split for each recipient. So, in this case, if the listener decided to pay 100 satoshis per minute for listening
|
|
to this podcast, then once per minute the "Host" would be sent 50 satoshis, the "Co-Host" would be sent 40 satoshis and the
|
|
"Producer" would be sent 10 satoshis - all to their respective lightning node addresses using the "keysend" protocol.
|
|
|
|
If, instead of a 50/40/10 (total of 100) split, the splits were given as 190/152/38 (total of 380), the respective payment amounts each minute would still
|
|
be 50 satoshis, 40 satoshis and 10 satoshis because the listener chose to pay 100 satoshis per minute, and the respective shares (as a percentage of the total) would remain the same.
|
|
|
|
On a 190/152/38 split, each minute the payment calculation would be:
|
|
|
|
- Interval payout: 100 satoshis
|
|
|
|
- Share total: 380
|
|
|
|
- Recipient #1 gets a payment of: 50 sats (190 / 380 * 100)
|
|
- Recipient #2 gets a payment of: 40 sats (152 / 380 * 100)
|
|
- Recipient #3 gets a payment of: 10 sats (38 / 380 * 100)
|
|
|
|
If an app chooses to only make a payout once every 30 minutes of listening/watching, the calculation would be the same after multiplying
|
|
the per-minute payment by 30:
|
|
|
|
- Interval payout: 3000 satoshis (100 * 30)
|
|
|
|
- Shares total: 380
|
|
|
|
- Recipient #1 gets a payment of: 1500 sats (190 / 380 * 3000)
|
|
- Recipient #2 gets a payment of: 1200 sats (152 / 380 * 3000)
|
|
- Recipient #3 gets a payment of: 300 sats (38 / 380 * 3000)
|
|
|
|
As shown above, the once per minute calculation does not have to actually be sent every minute. A longer payout period can be chosen. But,
|
|
the once-per-minute nature of the payout still remains in order for listeners and creators to have an easy way to measure and calculate how much
|
|
they will spend and charge.
|
|
|
|
<br><br>
|
|
|
|
<div class="page"/>
|
|
|
|
### Supported Currencies and Protocols
|
|
|
|
The value block is designed to be flexible enough to handle most any cryptocurrency, and even fiat currencies with a given
|
|
API that exposes a compatible process.
|
|
|
|
Currently, development is centered fully on [Lightning](https://github.com/lightningnetwork) using the "keysend" protocol. Keysend allows for push
|
|
based payments without the recipient needing to generate an invoice to receive them.
|
|
|
|
<br>
|
|
|
|
#### Lightning
|
|
|
|
For the `<podcast:value>` tag, the following attributes MUST be used:
|
|
|
|
- `type` (required): "lightning"
|
|
- `method` (required): "keysend"
|
|
- `suggested` (optional): An integer representing millisatoshis.
|
|
|
|
For the `<podcast:valueRecipient>` tag, the following attributes MUST be used:
|
|
|
|
- `type`: "node"
|
|
- `address`: \<the destination node's pubkey\>
|
|
- `split`: \<the number of shares\>
|
|
|
|
If the receiving Lightning node, or service, requires a custom record or meta-data of some sort to be passed along with the payment
|
|
the `customKey` and `customValue` can be utilized as follows:
|
|
|
|
- `type`: "node"
|
|
- `method`: "keysend"
|
|
- `customKey`: \<key name\>
|
|
- `customValue`: \<value\>
|
|
- `address`: \<the destination node's pubkey\>
|
|
- `split`: \<the number of shares\>
|
|
|
|
<br>
|
|
|
|
##### Example
|
|
|
|
This is a live, working example of a Lightning keysend value block in production. It designates four recipients for payment - two
|
|
podcast hosts at 49 and 46 shares respectively, a producer working on per episode chapter creation who gets a 5 share, and
|
|
a single share (effectively 1%) donation to Podcastindex.org.
|
|
|
|
```
|
|
<podcast:value type="lightning" method="keysend" suggested="0.00000015000">
|
|
<podcast:valueRecipient
|
|
name="Adam Curry (Podcaster)"
|
|
type="node"
|
|
address="02d5c1bf8b940dc9cadca86d1b0a3c37fbe39cee4c7e839e33bef9174531d27f52"
|
|
split="49"
|
|
/>
|
|
<podcast:valueRecipient
|
|
name="Dave Jones (Podcaster)"
|
|
type="node"
|
|
address="032f4ffbbafffbe51726ad3c164a3d0d37ec27bc67b29a159b0f49ae8ac21b8508"
|
|
split="46"
|
|
/>
|
|
<podcast:valueRecipient
|
|
name="Dreb Scott (Chapter Creation)"
|
|
type="node"
|
|
address="02dd306e68c46681aa21d88a436fb35355a8579dd30201581cefa17cb179fc4c15"
|
|
split="5"
|
|
/>
|
|
<podcast:valueRecipient
|
|
name="Podcastindex.org (Donation)"
|
|
type="node"
|
|
address="03ae9f91a0cb8ff43840e3c322c4c61f019d8c1c3cea15a25cfc425ac605e61a4a"
|
|
split="1"
|
|
/>
|
|
</podcast:value>
|
|
```
|