Receipt Verifier Service
This page explains how to set up a receipt verifier service.
As more creators adopt Web Monetization to serve premium and/or ad-free content, there’s a greater need for reliable payment verification. Web Monetization browser events, like monetizationstart
, are helpful indicators of payment, but can be spoofed by savvy users to access exclusive content without paying.
Interledger STREAM receipts provide payment recipients (such as web monetized site owners) with verifiable proofs of payment. As a payment recipient, you can verify STREAM receipts yourself by setting up your own receipt verifier service or by using a third-party service, like the one we provide. You don't need to run your own Interledger connector or SPSP server to verify STREAM receipts.
Before you begin
Your Web Monetization receiver (the digital entity receiving payments) must be set up to generate Interledger STREAM receipts. No action is required on your part. GateHub and Uphold already support receipts.
Receipt verifier service overview
The receipt verifier service acts as a proxy between the Web Monetization sender and receiver.
Before a payment is made, the WM sender sends a query to the WM receiver. The query passes through the receipt verifier service, which adds a receipt secret and receipt nonce.
When the WM receiver receives money from the payment, it generates a receipt (which includes a signature generated using the receipt secret) and sends the receipt to the WM sender.
The site takes the receipt from the Web Monetization events, then submits the receipt to its backend. The backend then submits the receipt to the receipt verifier service so the receipt verifier service can confirm the payment (as only it and the WM receiver know the receipt secret). The receipt verifier service must verify the receipt before accepting the amount as paid.
Use our publicly available receipt verifier
If you don't want to set up your own receipt verifier service, you can use ours!
Review the following sections below and use https://webmonetization.org/api/receipts
as the receipt verifier service's URL.
Install the receipt verifier service package
You can get the receipt verifier service package or run the receipt verifier service as a Kubernetes service.
Example
This example shows Coil's implementation of the receipt verifier service package, which requires Redis. You can write a different implementation that doesn't rely on Redis.
npm install
npm run-script build
sudo docker run -p 6379:6379 -d redis
npm start
git clone https://github.com/coilhq/receipt-verifier.git
cd receipt-verifier
Update your Web Monetization meta tag
Typically, a Web Monetization meta tag looks something like this:
<meta name=“monetization" content="$wallet.example/alice">
For queries from the WM sender to be proxied by the receipt verifier service to your payment pointer:
- URI-encode your payment pointer. See encodeURIComponent() on MDN Web Docs if you need help.
- Add your pointer to the path of the receipt verifier service's URL.
- Update your meta tag's
content
to be this new value.
For example, if your payment pointer is $wallet.example/alice
and your receipt verifier service’s URL is https://receipt-verifier.example
, then you’ll set your meta tag’s content
to either of the following:
https://receipt-verifier.example/%24wallet.example%2Falice
$receipt-verifier.example/%24wallet.example%2Falice
If you're using our publicly available receipt verifier service, then you'll set your meta tag's content
to either of the following:
https://webmonetization.org/api/receipts/%24wallet.example%2Falice
$webmonetization.org/api/receipts/%24wallet.example%2Falice
You can create your meta tag with the Meta Tag Generator if using the publicly available receipt verifier service.
Web Monetization revshare generator
If you used the Web Monetization revshare generator to create a meta tag for probabilistic revenue sharing, follow the same instructions as above: URI-encode your revshare payment pointer and put it in the path of the receipt verifier service’s URL.
For example, if your meta tag looks like this:
<meta name="monetization" content="$webmonetization.org/api/revshare/pay/W1siJHdhbGxldC5leGFtcGxlL2FsaWNlIiwxMCwiQWxpY2UiXSxbIiR3YWxsZXQuZXhhbXBsZS9ib2IiLDEwLCJCb2IiXV0">
And your receipt verifier service’s URL is https://receipt-verifier.example
, then you’ll set your meta tag’s content
to either of the following:
https://receipt-verifier.example/%24webmonetization.org%2Fapi%2Frevshare%2Fpay%2FW1siJHdhbGxldC5leGFtcGxlL2FsaWNlIiwxMCwiQWxpY2UiXSxbIiR3YWxsZXQuZXhhbXBsZS9ib2IiLDEwLCJCb2IiXV0
$receipt-verifier.example/ %24webmonetization.org%2Fapi%2Frevshare%2Fpay%2FW1siJHdhbGxldC5leGFtcGxlL2FsaWNlIiwxMCwiQWxpY2UiXSxbIiR3YWxsZXQuZXhhbXBsZS9ib2IiLDEwLCJCb2IiXV0
Set up a monetizationprogress event listener
When a WM sender receives a receipt, the sender notifies the user agent of the successful payment by submitting a monetizationprogress
event containing a receipt.
Add the following client-side code to your website to listen for a monetizationprogress
event containing a receipt
. When a receipt exists, your website will verify the receipt in the event listener to confirm the payment.
<head>
<!-- This should be set to .... -->
<meta name="monetization" content="https://receipt-verifier.example/%24wallet.example%2Falice" />
<script>
if (document.monetization) {
document.monetization.addEventListener('monetizationprogress', event => {
// A payment has been received.
// Connect to your site’s backend to validate the payment. This does NOT connect directly to the receipt verifier.
const res = await fetch('/verifyReceipt', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
receipt: event.detail.receipt
})
})
})
}
</script>
</head>
Your backend can send the receipt to the receipt verifier service’s /verify
endpoint.
If you're using our publicly available receipt verifier service, the verify endpoint is https://webmonetization.org/api/receipts/verify
.
Here’s an example for an Express.js server:
app.post('/verifyReceipt', async (req, res) => {
const resp = await fetch('https://receipt-verifier.example/verify', {
method: 'POST',
body: req.body.receipt
}
const { amount } = await resp.json()
console.log('Received ' + amount)
// backend logic for new paid amount
})
The receipt verifier service can confirm the payment, as only the receipt verifier service and the WM receiver know the receipt secret. The receipt verifier service must verify the receipt before accepting the receipt amount as paid. When accepted as paid, the site backend can serve exclusive content or any other perks you’ve set up.