Thread

Article header

Open Podcast Payments with Bitcoin and Nostr

Open podcasting needs interoperable payments - and Bitcoin and Nostr provide the payment and metadata layers to make this possible

Podcasting is unique in that it has remained relatively decentralised with many different apps and hosting providers.

Creators can choose where to host their show, distribute to any app, and then switch hosts without losing data or interrupting the listener experience. Listeners can choose any app to listen on, and can easily switch apps whilst maintaining their list of followed shows.

RSS has made this possible - but payments have historically not been part of the spec. Although some hosting companies and external services do offer proprietary payment capabilities for podcasters, these services break the open and interoperable nature of podcasting.

Podcasting 2.0 is bringing RSS into the future - and with the introduction of the <podcast:value> tag has given podcasters a way to receive listener payments from any app in an open way. Podcasters can add the value tag at either the feed or item level and split payments between multiple recipients such as co-hosts or guests.


Moving Away from Keysend

Originally the <podcast:value> spec used keysend to facilitate payments.

Whilst keysend worked well initially, there is consensus within the Podcasting 2.0 community that it is not a long-term solution because many of the most popular Lightning Wallets such as Strike, CashApp, Primal, Wallet of Satoshi do not support it.

The Lightning Address has also become the de-facto standard for sharing payment information in an easy way. "Like an email address, but for money" - is an easy to understand concept for anyone even if they are new to Bitcoin, and asking someone to share their Lightning Address is simple.

Because of this the Podcasting 2.0 spec has been updated to use type="lnaddress" - allowing podcasters to simply add one or more Lightning Addresses into their RSS feeds to instruct apps where to send payments:

<podcast:value type="lightning">
  <podcast:valueRecipient
    name="Oscar"
    type="lnaddress"
    address="merryoscar@fountain.fm" 
    split="100"
  />
</podcast:value>

Sharing Payment Metadata Between Apps

Adding a Lightning Address to your RSS feed enables any podcast app to send payments in an open and interoperable way.

But there's also a need to share metadata about the payment:

  • Which episode was the payment related to?

  • Who sent the payment?

  • Was there a message included with the payment?

This payment metadata enables richer experiences to be created in podcast apps - for example Fountain uses social payments as a signal for what episodes are worth listening to.

Fountain uses Nostr to share both payment metadata and comments in an open interoperable way so that other apps can query and render the data:

Cross App Podcast Payments

Whilst there is still debate within the Podcasting 2.0 community around the best way to share payment metadata - my view is that Nostr provides the perfect solution:

Combining these two specs allows podcast apps to share payment metadata such that any other app or service can query the data.

The next section is a step-by-step guide for podcast app developers that want to share payment metadata using Nostr.


Implementing Cross-App Podcast Payments

The guide assumes that your app has the capability to pay BOLT-11 Lightning Invoices, and that you have a basic understanding of the nostr protocol.

The steps are as follows:

1) Read the Lightning Address from the RSS Feed
<podcast:value type="lightning">
  <podcast:valueRecipient
    name="Oscar"
    type="lnaddress"
    address="merryoscar@fountain.fm" 
    split="100"
  />;
</podcast:value>
2) Sign a Zap Request including the Podcast GUID Tags

The zap request contains all of the payment metadata - including the NIP-73 k and i tags that reference which show / episode the payment relates to:

  • the pubkey field identifies the person sending the payment

  • the content field contains an optional message from the user sending the payment

  • the tags field contains additional metadata about the payment:

    • relays - the set of relays the zap receipt should be published to

    • amount - the payment amount in millisatoshis

    • k - the NIP-73 external content id kinds

    • i - the NIP-73 external content id values - with optional url hints to the show / episode pages

{
  "kind": 9734,
  "content": "Great episode!",
  "tags": [
    [
      "relays",
      "wss://relay.fountain.fm"
    ],
    [
      "amount",
      "21000"
    ],
    [
      "k",
      "podcast:guid"
    ],
    [
      "k",
      "podcast:item:guid"
    ],
    [
      "i",
      "podcast:guid:c90e609a-df1e-596a-bd5e-57bcc8aad6cc",
      "https://fountain.fm/show/p8WM5xdhPOB2YrKmP1Vy"
    ],
    [
      "i",
      "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f",
      "https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg"
    ]
  ],
  "pubkey": "{app_user_pubkey}",
  "created_at": 1679673265,
  "id": "",
  "sig": ""
}
3) Request the BOLT-11 Invoice from the Lightning Address

When requesting the BOLT-11 invoice from the Lightning Address - pass the zap request as a query parameter to the LNURL callback:

const sats = 21
const amount = sats * 1000
const callback = "" // lnurl pay http callback url

const event = encodeURI(JSON.stringify(event))
const {pr: invoice} = await fetch(`${callback}?amount=${amount}&nostr=${event}`)

Passing the zap request is what instructs the Lightning Address server to publish a zap receipt when the invoice is paid.

4) Query the Relay to Verify the Payment Was Made

You can query any nostr relay with a simple nostr filter JSON payload:

[
  "REQ",
  "{random_subscription_id}",
  {
    "authors": ["{app_user_pubkey}"]
    "#i": ["podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f"]
  }
]

To check the zap receipt was published - query one of the relays you specified in the zap request.

5) (OPTIONAL) Publish the Payment as a Comment

This last step is optional - but if you want the payment to appear in apps like Fountain and other nostr clients, and have interactions like likes / replies / reposts - you can quote the zap receipt as a NIP-19 encoded entity.

Don't worry if that sounds complex - it's actually very simple and there are libraries for all coding languages that make it very easy.

Quoting a zap receipt is like quoting any other event in nostr - except rather than quoting a post - you are quoting a payment.

There are different ways to format these posts - but Fountain structures them like this:

{
  "kind": 1,
  "content": "{message}\n\n{content_link}\n\n{nostr:nevent}"
}
  • the {message} is the users message

  • the {content_link} is a link to the episode or show - this helps to add context for the note in nostr clients that don't know how to resolve the podcast guid tags

  • the {nostr:nevent} is the encoded zap receipt - clients like Primal know how to render these including the payment amount:

nostr:nevent1qvzqqqqqqypzpe8kjhc9hvzmyvf9tnxw84r3hrtece9xt0xvq9rx95nlpalfyyyjqqszkzt48zk8ukmlhzx4el2mtjt27mmudcg2parfl7uhwca38cvh93swehha4


The Future of Cross-App Podcast Payments

Hey you made it this far - thanks for reading!

Interoperable social payments will help ensure open podcasting remains the best place to publish and listen to long-form content.

Although Fountain has implemented social payments, the real unlock will be when multiple apps are publishing this payment metadata, enabling value-driven discovery and conversation to happen between different apps.

In the spirit of open payments why don't you give this article a zap so I know it was valuable - and leave a comment with your thoughts.

Replies (3)

This is great, Oscar. Thanks for such a thorough write up. I am going to essentially copy and paste this whole article 😂 into Claude and get this added to Podstr. I would LOVE to see @Soapbox Sessions boosts and comments show up in Podstr. Fingers crossed that I can get it to work!
How about just open source the code?
🛡️
Payments feature is useful only for popular shows ! They too can't make ends just through podcast payments .. I mean even a show like "no agenda" has very little v4v money coming in .. compared to what it could if it had sponsors .. So , I am not sure if we need to solve a problem which anyway has no solution.. podcasting would thrive because it is what people want to do .. and audience want to listen .. v4v is just a token .. Some things are beyond mere commercial value .. and that is a good thing ..