{"number":121,"title":"Proof of Payment URI scheme","authors":["Kalle Rosenbaum"],"status":"Closed","type":"Specification","layer":"Applications","created":"2015-07-27","requires":[],"replaces":[],"replacedBy":[],"discussion":[],"abstract":"This is a proposal for a URI scheme to be used in the Proof of Payment process.","eli5":"Defines a link format (URI) for requesting a Proof of Payment, as described in BIP 120. A service can present such a link or QR code, and the user's wallet can respond by proving it made the relevant payment.","categories":["scripts"],"filename":"bip-0121.mediawiki","githubUrl":"https://github.com/bitcoin/bips/blob/master/bip-0121.mediawiki","format":"mediawiki","readingMinutes":3,"inbound":1,"revisions":19,"impact":57,"core":false,"references":[],"lastModified":"2025-10-08","html":"<h2 id=\"abstract\">Abstract</h2>\n<p>This is a proposal for a URI scheme to be used in the Proof of Payment process.</p>\n<h2 id=\"motivation\">Motivation</h2>\n<p>To make a Proof of Payment, the party that wants the proof needs to transfer a Proof of Payment request to the wallet software of the other party. To facilitate that transfer, a new URI scheme representing the PoP request is proposed. This URI can then be encoded in QR images or be sent over NFC in order to transfer it to the wallet.</p>\n<h2 id=\"specification\">Specification</h2>\n<p>The specification is the same as BIP0021, with the following differences:</p>\n<ul><li>\nThe URI scheme is <code>btcpop</code> instead of <code>bitcoin</code>\n</li></ul>\n<ul><li>\nThe path component, i.e. the address part, is always empty.\n</li></ul>\n<ul><li>\nA mandatory <code>p</code> parameter whose value contains the destination for the PoP. This could for example be a <code>https:</code> URL or a <code>mailto:</code> URI.\n</li></ul>\n<ul><li>\nA mandatory <code>n</code> parameter representing the nonce, base58 encoded.\n</li></ul>\n<ul><li>\nAn optional <code>txid</code> parameter containing the Base58 encoded hash of the transaction to prove.\n</li></ul>\n<p>Just as in BIP0021, elements of the query component may contain characters outside the valid range. These must first be encoded according to UTF-8, and then each octet of the corresponding UTF-8 sequence must be percent-encoded as described in RFC 3986.</p>\n<p>All parameters except <code>p</code> and <code>n</code> are hints to the wallet on which transaction to create a PoP for.</p>\n<p>The extensibility of BIP0021 applies to this scheme as well. For example, a <code>date</code> parameter or a <code>toaddr</code> parameter might be useful. <code>req-*</code> parameters are also allowed and obey the same rules as in BIP0021, clients not supporting a <code>req-*</code> parameter must consider the URI invalid.</p>\n<h3 id=\"keep-uris-short\">Keep URIs short</h3>\n<p>Implementations should keep the URIs as short as possible. This is because it makes QR decoding more stable. A camera with a scratched lens or low resolution may run into problems scanning huge QR codes. This is why the <code>txid</code> parameter is encoded in Base58 instead of the classic hex encoded string. We get away with 44 characters instead of 64. Also, the <code>nonce</code> parameter is Base58 encoded for the same reason.</p>\n<h2 id=\"interpretation\">Interpretation</h2>\n<h3 id=\"transaction-hints\">Transaction hints</h3>\n<p>The wallet processing the URI must use the hints in the PoP request to filter its transaction set. The <code>label</code>, <code>amount</code> and <code>message</code> parameters must, if present in the URI, exactly match the data associated with the original payment according to the following table:</p>\n<div class=\"table-wrap\"><table><tbody><tr><td><code>btcpop:</code> URI parameter</td><td><code>bitcoin:</code> URI parameter</td><td>BIP70 PaymentDetails data</td></tr><tr><td><code>label</code></td><td><code>label</code></td><td><code>memo</code></td></tr><tr><td><code>amount</code></td><td><code>amount</code></td><td><code>sum of outputs.amount</code></td></tr><tr><td><code>message</code></td><td><code>message</code></td><td><code>-</code></td></tr></tbody></table></div>\n<p>The <code>txid</code> parameter value must match the transaction hash of the payment.</p>\n<p>After filtering, the resulting transaction set is displayed to the user who selects one of them to prove. An implementation could also automatically select a transaction in the filtered set, but there must still be a way for the user to select freely among the matching transactions. If the filtered set is empty, no transaction fits the hints and a message about that is presented to the user. If the filtered set contains exactly one transaction, which is preferable, that transaction can be automatically selected.</p>\n<p>As a fallback, there must also be a way for the user to select any transaction from the wallet regardless of the transaction hints. This can be useful if the metadata of the wallet is lost, possibly due to a restore from backup.</p>\n<h3 id=\"pop-destination-p\">PoP destination <code>p</code></h3>\n<p>The <code>p</code> parameter value is the destination where to send the PoP to. This destination is typically a <code>https:</code> URL or a <code>http:</code> URL, but it could be any type of URI, for example <code>mailto:</code>. To keep <code>btcpop:</code> URIs short, users should not make their <code>p</code> parameter unnecessarily long.</p>\n<h4 id=\"http-and-https-urls\"><code>http:</code> and <code>https:</code> URLs</h4>\n<p>Wallet implementations must support the <code>http:</code> and <code>https:</code> schemes in which case <code>POST</code> method must be used. The PoP is sent as a binary serialized transaction. The content type of the POST request must be set to <code>application/bitcoin-pop</code></p>\n<h2 id=\"examples\">Examples</h2>\n<p>Send PoP for a transaction with label \"video 42923\" to https://www.example.com/pop/352, using nonce <code>0x73 0xd5 0x1a 0xbb 0xd8 0x9c</code>:</p>\n<pre><code> btcpop:?p=https://www.example.com/pop/352&n=zgWTm8yH&label=video%2042923</code></pre>\n<p>Send PoP through mail using mailto:pop@example.com?subject=pop444, amount is 13370000 satoshis, nonce is <code>0x6f 0xe 0xfb 0x68 0x92 0xf9</code>. Note that the <code>?</code> before <code>subject</code> is OK according to RFC3986, since the query part starts from the first <code>?</code>:</p>\n<pre><code> btcpop:?p=mailto:pop@example.com?subject%3Dpop444&n=xJdKmEbr&amount=0.1337</code></pre>\n<p>Send PoP for transaction with id <code>cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79</code> to pizza place at http://pizza.example.com/pop/laszlo111 using nonce <code>0xfc 0xcc 0x2c 0x35 0xf0 0xb8</code></p>\n<pre><code> btcpop:?p=http://pizza.example.com/pop/laszlo111&n=3AtNpVrPh&txid=Emt9MPvt1joznqHy5eEHkNtcuQuYWXzYJBQZN6BJm6NL</code></pre>\n<h2 id=\"reference-implementation\">Reference implementation</h2>\n<p><a href=\"https://github.com/kallerosenbaum/poppoc\">PoP Demo server on GitHub</a></p>\n<p><a href=\"https://github.com/kallerosenbaum/wallet\">PoP-enabled Mycelium fork on GitHub</a></p>\n<h2 id=\"references\">References</h2>\n<p><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki\">BIP0021</a>: URI Scheme</p>\n<p><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0120.mediawiki\">BIP0120</a>: Proof of Payment</p>\n<p><a href=\"https://www.ietf.org/rfc/rfc3986.txt\">RFC3986</a>: Uniform Resource Identifier (URI): Generic Syntax</p>","toc":[{"id":"abstract","title":"Abstract","level":2},{"id":"motivation","title":"Motivation","level":2},{"id":"specification","title":"Specification","level":2},{"id":"keep-uris-short","title":"Keep URIs short","level":3},{"id":"interpretation","title":"Interpretation","level":2},{"id":"transaction-hints","title":"Transaction hints","level":3},{"id":"pop-destination-p","title":"PoP destination p","level":3},{"id":"http-and-https-urls","title":"http: and https: URLs","level":4},{"id":"examples","title":"Examples","level":2},{"id":"reference-implementation","title":"Reference implementation","level":2},{"id":"references","title":"References","level":2}],"history":{"totalCommits":19,"firstCommit":"2015-07-28T22:41:35+02:00","lastUpdated":"2025-10-08T14:59:36-07:00","events":[{"sha":"24e96e870fffaa257b465ce1f0370c14aac588e8","date":"2025-10-08T14:59:36-07:00","author":"Murch","message":"process: Created ↦ Assigned","url":"https://github.com/bitcoin/bips/commit/24e96e870fffaa257b465ce1f0370c14aac588e8","kind":"edit"},{"sha":"5207ef92a52d0b8902895b0dbb40823a4d698ec9","date":"2025-04-11T20:08:17-07:00","author":"Murch","message":"process: Author ↦ Authors","url":"https://github.com/bitcoin/bips/commit/5207ef92a52d0b8902895b0dbb40823a4d698ec9","kind":"edit"},{"sha":"59730dec4fb641a41589aa1b91d3c452f13e0e36","date":"2025-04-11T20:05:13-07:00","author":"Murch","message":"process: Remove Comments-URI and -Summary","url":"https://github.com/bitcoin/bips/commit/59730dec4fb641a41589aa1b91d3c452f13e0e36","kind":"edit"},{"sha":"a233bde4af52c6a11269e2e6dd9707abce441ffe","date":"2025-04-11T18:19:21-07:00","author":"Murch","message":"process: Standards Track ↦ Specification","url":"https://github.com/bitcoin/bips/commit/a233bde4af52c6a11269e2e6dd9707abce441ffe","kind":"edit"},{"sha":"66defbdc03ad64ccddfd373e1c59af9a41ab990f","date":"2025-04-11T18:11:55-07:00","author":"Murch","message":"process: Deferred/Obsolete/Rejected/Replaced/Withdrawn ↦ Closed","url":"https://github.com/bitcoin/bips/commit/66defbdc03ad64ccddfd373e1c59af9a41ab990f","kind":"status"},{"sha":"85a99fb14b64234aa59492649c30e3bd2f04e28d","date":"2018-02-08T22:22:50+01:00","author":"Kalle Rosenbaum","message":"Withdrawing BIP120/121 due to security issues during soft-forks","url":"https://github.com/bitcoin/bips/commit/85a99fb14b64234aa59492649c30e3bd2f04e28d","kind":"edit"},{"sha":"959fecc15bdad070afa63455468b1dba54655fa6","date":"2016-11-30T09:47:31+00:00","author":"Luke Dashjr","message":"Promote BIP 2 Draft->Active, and implement it","url":"https://github.com/bitcoin/bips/commit/959fecc15bdad070afa63455468b1dba54655fa6","kind":"status"},{"sha":"72f18918a8ae655212ea2700b30f0dc4d758b843","date":"2016-11-30T09:45:33+00:00","author":"Luke Dashjr","message":"Promote BIP 123 Draft->Active, and implement it","url":"https://github.com/bitcoin/bips/commit/72f18918a8ae655212ea2700b30f0dc4d758b843","kind":"status"},{"sha":"a429841781725fa5da54649aa836bb34868bab52","date":"2015-10-27T14:25:27+01:00","author":"Kalle Rosenbaum","message":"Clarified that the PoP is sent as binary over http","url":"https://github.com/bitcoin/bips/commit/a429841781725fa5da54649aa836bb34868bab52","kind":"edit"},{"sha":"05451a239e42bca4c813e51c869309d0d24efc78","date":"2015-10-27T14:18:00+01:00","author":"Kalle Rosenbaum","message":"Removed mapping of merchant_data to btcpop-label since merchant data is a byte-array, Thanks Andreas Schildbach.  Instead map the memo field to btcpop-label and don't have any bip70 field mapped to btcpop-message.","url":"https://github.com/bitcoin/bips/commit/05451a239e42bca4c813e51c869309d0d24efc78","kind":"edit"},{"sha":"61b865e5241be45437ece5fe70ae6e6c2319cbb9","date":"2015-10-20T15:38:14+02:00","author":"Jonathan Cross","message":"Spelling fix.","url":"https://github.com/bitcoin/bips/commit/61b865e5241be45437ece5fe70ae6e6c2319cbb9","kind":"edit"},{"sha":"e313067d01442a1be86f007a48f7900cba720aa5","date":"2015-09-25T14:36:45+02:00","author":"Kalle Rosenbaum","message":"Removing unnecessary http header Content-Transfer-Encoding. That is only used for e-mail.","url":"https://github.com/bitcoin/bips/commit/e313067d01442a1be86f007a48f7900cba720aa5","kind":"edit"},{"sha":"10173c76ccef3a8766538d9029edfab12b620797","date":"2015-09-17T15:10:27+02:00","author":"Kalle Rosenbaum","message":"Fixed unencoded space character in example","url":"https://github.com/bitcoin/bips/commit/10173c76ccef3a8766538d9029edfab12b620797","kind":"edit"},{"sha":"3d1eb28f8412360d1cefee3c556619ad30dff830","date":"2015-08-07T19:06:18+02:00","author":"Kalle Rosenbaum","message":"Adding BIP0121","url":"https://github.com/bitcoin/bips/commit/3d1eb28f8412360d1cefee3c556619ad30dff830","kind":"edit"},{"sha":"0cf2419511ed30b495f8821b62f67407d438cbbf","date":"2015-08-07T19:02:36+02:00","author":"Kalle Rosenbaum","message":"Removing bips and will add them again one at a time.","url":"https://github.com/bitcoin/bips/commit/0cf2419511ed30b495f8821b62f67407d438cbbf","kind":"edit"},{"sha":"8921a74d4384e9790c3c0bb256f529ffe8c1fa92","date":"2015-08-07T18:54:07+02:00","author":"Kalle Rosenbaum","message":"More formatting. Trying to get dummy URLs to not display as links.","url":"https://github.com/bitcoin/bips/commit/8921a74d4384e9790c3c0bb256f529ffe8c1fa92","kind":"edit"},{"sha":"e958c59d2aa8a86c78d59ba8b5e0ed552937fd38","date":"2015-08-07T18:41:19+02:00","author":"Kalle Rosenbaum","message":"Testing formatting","url":"https://github.com/bitcoin/bips/commit/e958c59d2aa8a86c78d59ba8b5e0ed552937fd38","kind":"edit"},{"sha":"e0b32222d0d8f9fae1b47dca8380be48a9a29d43","date":"2015-08-07T18:37:17+02:00","author":"Kalle Rosenbaum","message":"Fixing markup","url":"https://github.com/bitcoin/bips/commit/e0b32222d0d8f9fae1b47dca8380be48a9a29d43","kind":"edit"},{"sha":"4b6ee39ced3c6d838cee1827a5585620f7e188f5","date":"2015-07-28T22:41:35+02:00","author":"Kalle Rosenbaum","message":"Added BIP0120 and BIP0121","url":"https://github.com/bitcoin/bips/commit/4b6ee39ced3c6d838cee1827a5585620f7e188f5","kind":"edit"}]}}