{"number":77,"title":"Async Payjoin","authors":["Dan Gould","Yuval Kogman"],"status":"Draft","type":"Specification","layer":"Applications","created":"2023-08-08","license":"BSD-2-Clause","version":"0.2.0","requires":[21,78,173,174],"replaces":[],"replacedBy":[],"discussion":["https://github.com/bitcoin/bips/pull/1483","https://gnusha.org/pi/bitcoindev/7B11AE34-27A7-46ED-95BF-66CA13BA26F3@ngould.dev/#t","https://gnusha.org/pi/bitcoindev/3C0A6E4C-444E-4E75-829C-1A21D8EE40E0@ngould.dev/#t"],"comments":"https://github.com/bitcoin/bips/wiki/Comments:BIP-0077","abstract":"Payjoin lets Bitcoin senders and receivers interact to make batched transactions. This document proposes a second, backwards-compatible, asynchronous version of the Payjoin protocol (\"Version 2\") relative to and described in BIP 78 (\"Version 1\"). An untrusted third-party \"directory server\" replaces the requirement for a receiver to host a secure public endpoint for interactions. HTTP clients access the directory server using an asynchronous protocol and authenticated, encrypted payloads. The design preserves complete Payjoin receiver functionality, including payment output substitution. Authenticated encryption depends only on cryptographic primitives available in Bitcoin Core. Requests use Oblivious HTTP (OHTTP) to prevent the directory and other Payjoin clients from linking requests to client IP addresses.","eli5":"Introduces a second version of Payjoin that works asynchronously, so sender and receiver do not need to be online at the same moment. An untrusted relay called a directory server passes encrypted messages between them, meaning ordinary wallets can receive Payjoin payments without running their own web server.","categories":["addresses","transactions"],"filename":"bip-0077.md","githubUrl":"https://github.com/bitcoin/bips/blob/master/bip-0077.md","format":"markdown","readingMinutes":20,"inbound":0,"revisions":14,"impact":23,"core":false,"references":[],"lastModified":"2026-06-01","html":"<h2 id=\"copyright\">Copyright</h2>\n<p>This BIP is licensed under the 2-clause BSD license.</p>\n<h2 id=\"abstract\">Abstract</h2>\n<p>Payjoin lets Bitcoin senders and receivers interact to make batched\ntransactions.</p>\n<p>This document proposes a second, backwards-compatible, asynchronous version of\nthe Payjoin protocol (&quot;Version 2&quot;) relative to and described in <a href=\"/bip/78\">BIP 78</a> (&quot;Version 1&quot;). An untrusted\nthird-party &quot;directory server&quot; replaces the requirement\nfor a receiver to host a secure public endpoint for interactions. HTTP clients\naccess the directory server using an asynchronous protocol and authenticated,\nencrypted payloads. The design preserves complete Payjoin receiver\nfunctionality, including payment\noutput substitution. Authenticated encryption depends only on cryptographic\nprimitives available in Bitcoin Core. Requests use <a href=\"https://www.ietf.org/rfc/rfc9458.html\">Oblivious\nHTTP</a> (OHTTP) to\nprevent the directory and other Payjoin clients from linking requests to client\nIP addresses.</p>\n<h2 id=\"motivation\">Motivation</h2>\n<p>Satoshi Nakamoto pointed out one specific privacy risk in the\n<a href=\"https://bitcoin.org/en/bitcoin-paper\">whitepaper</a>,\nthat transactions with multiple inputs &quot;necessarily reveal that\ntheir inputs were owned by the same owner.&quot;\nPayjoin addresses that risk, the <em>common-input-ownership heuristic</em>,\nby making it practical to spend inputs owned by multiple parties\nin one transaction.</p>\n<p>While addressing Bitcoin&#39;s primal privacy risk, Payjoin <em>input</em> batching\nalso improves on the widespread non-interactive <em>output</em> batching practice\ndeployed by exchanges. When combined, the same movement of funds can use\nless block weight and save fees.</p>\n<p>A natural application of Payjoin would be to combine\ngetting paid with consolidating UTXOs into one transaction. But Payjoin\ncan also secure <a href=\"https://bitcointalk.org/index.php?topic=281848.0\">transaction\ncut-through</a>,\nallowing a sender to transfer funds to a receiver who also transfers\nfunds to a third party in the same transaction. For example, deposits to an\nexchange may &quot;cut through&quot; in a single transaction that also satisfies\nwithdrawals instead of with a second transaction that spends the deposited\nfunds. Payjoin enables more blockspace-efficient transactions that\nreduce fees while addressing privacy risks.</p>\n<p>However, BIP 78&#39;s requirements for Payjoin Version 1 have proven to be an\nobstacle to adoption. Version 1 receivers must host a secured\npublic-facing HTTP server. Mobile and web environments limit the ability\nto fulfil such a requirement. Version 1 also requires synchronous\ncommunication. Both sender and receiver must be online simultaneously.\nWallet developers <a href=\"https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html\">\nregard</a>\nthese requirements as barriers to Payjoin adoption.</p>\n<p>To address these limitations, our goal is to specify a practical\ncoordination mechanism suitable for widespread implementation. This proposal\nleverages mature solutions to common problems, building on established web\nstandards and proven Bitcoin primitives.</p>\n<h2 id=\"overview\">Overview</h2>\n<p>A Payjoin <em>sender</em> and <em>receiver</em> interact so that they may both contribute to a\ntransaction. In this proposal, they exchange asynchronous end-to-end\nencrypted messages by relaying them to a store-and-forward <em>directory</em> server\nusing OHTTP.</p>\n<p>Before initiating the protocol, the receiver must secure communications with\nthe directory by <a href=\"#ohttp-bootstrapping\">bootstrapping</a>.</p>\n<ul>\n<li>The receiver <a href=\"#session-initiation\">initiates a Payjoin Session</a>\nby sharing a <a href=\"#payjoin-uri\">Payjoin URI</a> that includes the URL of an\nephemeral mailbox hosted on the directory, where it can receive a message\nfrom the sender.</li>\n<li>The sender <a href=\"#sender-original-psbt-messaging\">posts a message</a>\ncontaining a fully signed fallback transaction, known as the <em>Original PSBT</em>,\nto the mailbox.</li>\n<li>The receiver gets this message and\n<a href=\"#receiver-proposal-psbt-messaging\">posts a message containing a <em>Proposal\nPSBT</em></a>\nto the sender&#39;s ephemeral mailbox, by updating the Original PSBT with\nappropriate inputs and/or outputs.</li>\n<li>The sender gets the Proposal PSBT, <a href=\"#sender-signing-and-broadcast\">checks it, signs, and\nbroadcasts</a> the final transaction.</li>\n</ul>\n<p>At any point, either party may choose to broadcast the\nfallback transaction described by the Original PSBT instead of proceeding.\nBecause the Original PSBT and Proposal PSBT spend the same input(s) they are\nmutually exclusive and only one can be confirmed.</p>\n<p>Messages are buffered in the directory, allowing both parties to tolerate\ntemporary disconnections and resume communication by polling.</p>\n<h3 id=\"async-payjoin-directory-mediated-sequence-diagram\">Async Payjoin Directory Mediated Sequence Diagram</h3>\n<pre><code class=\"language-text\">  +----------+            +------------+            +----------+            +----------+\n  | Receiver |            | Directory  |            | Sender   |            | Network  |\n  +----+-----+            +-----+------+            +----+-----+            +----+-----+\n       |                        |                        |                       |\n       |  Payjoin URI (BIP21), out-of-band               |                       |\n       +------------------------------------------------&gt;|                       |\n       |                        |                        |                       |\n       |  Poll GET: original PSBT (repeat until available)                       |\n       +- - - - - - - - - - - -&gt;+                        |                       |\n       |                        #  POST: original PSBT   |                       |\n       |                        #&lt;-----------------------+                       |\n       |  200 OK: original PSBT #                        |                       |\n       |&lt;-----------------------+                        |                       |\n       |                        |                        |                       |\n       |                        |  Poll GET: proposal PSBT (repeat until available)\n       |                        +&lt;- - - - - - - - - - - -+                       |\n       |  POST: proposal PSBT   #                        |                       |\n       +-----------------------&gt;#                        |                       |\n       |                        #  200 OK: proposal PSBT |                       |\n       |                        +-----------------------&gt;|                       |\n       |                        |                        |                       |\n       |                        |                        |  Broadcast payjoin    |\n       |                        |                        +----------------------&gt;|\n       |                        |                        |                       |\n</code></pre>\n<h2 id=\"specification\">Specification</h2>\n<h3 id=\"ohttp-bootstrapping\">OHTTP Bootstrapping</h3>\n<p>Before initiating a Payjoin Session a receiver must first discover the\ndirectory&#39;s\n<a href=\"https://www.ietf.org/rfc/rfc9458.html#section-3.1\">OHTTP Key Configuration</a>,\nvia an authenticated\nbootstrap mechanism. The key configuration contains information to establish\n<a href=\"#secp256k1-hybrid-public-key-encryption\">Hybrid Public Key Encryption</a> (HPKE) in order to secure communications between the client and the directory in\nlieu of TLS.</p>\n<p>The bootstrap mechanism may vary by implementation but must\nfollow <a href=\"https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-key-consistency-01\">OHTTP Consistency\nRequirements</a>\nand should not reveal a receiver IP address to the directory. Some\nexamples of suitable mechanisms include getting a key configuration\nfrom a Payjoin URI, a trusted application binary, or fetching using https-in-http\nCONNECT method, https-in-WebSocket, Tor, or a VPN.</p>\n<p>Directory OHTTP Gateways MUST support <a href=\"https://www.rfc-editor.org/rfc/rfc9540.html#name-key-configuration-fetching\">RFC 9540 Key Configuration\nFetching</a>\nvia GET request. RFC 9540 defines the\ngateway location as <code>/.well-known/ohttp-gateway</code>.</p>\n<h3 id=\"session-initiation\">Session Initiation</h3>\n<p>A receiver initiates a session by sharing a Payjoin URI. Because a URI\ncontains sensitive information, such as a receiver address, it should be shared\nover a confidential channel.</p>\n<h4 id=\"payjoin-uri\">Payjoin URI</h4>\n<p>Bitcoin URIs (<a href=\"https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki\">BIP\n21</a>\nor <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0321.mediawiki\">BIP\n321</a>)\nare a standard way to request bitcoin.</p>\n<p>A Payjoin URI is a Bitcoin URI that contains a <code>pj</code> parameter. The <code>pj</code>\nparameter value is a URL in both BIP 78 and BIP 77.</p>\n<p>Senders that understand Bitcoin URI but don&#39;t support Payjoin will just\nignore the <code>pj</code> parameter and proceed to typical address-based\ntransaction flows.</p>\n<p>A <code>req-pj</code> parameter may be used as a <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki#forward-compatibility\">BIP 21 forwards compatibility <code>reqparam</code></a> instead of\n<code>pj</code> to signal that Payjoin is required.</p>\n<p>The parameter value must be <a href=\"#uppercase-url\">uppercased and the parameter should be placed last in the URI</a>.</p>\n<p>Since BIP 78 payloads are neither encrypted nor authenticated,\na directory used for backwards-compatible payloads is known\nas an <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#unsecured-payjoin-server\">&quot;unsecured payjoin server&quot; in BIP 78\nparlance</a>.\nBackwards-compatible receivers MUST disable output substitution\nby setting <code>pjos=0</code> to prevent modification by a malicious directory.</p>\n<h5>Mailbox endpoint</h5>\n<p>In this proposal the URL in the <code>pj</code> parameter value is the mailbox\nendpoint URL. Mailboxes are shared HTTP resources hosted by the\ndirectory and serve as OHTTP Target Resources. Clients use these endpoints\nto relay encrypted messages. They <code>POST</code> messages to and <code>GET</code> messages from\nmailbox endpoints via OHTTP.</p>\n<p>Senders that support BIP 78 but not this proposal may POST messages directly to\nmailbox endpoints for <a href=\"#backwards-compatibility\">backwards compatibility</a>.</p>\n<h6>Short ID</h6>\n<p>A Short ID identifies a mailbox based on its associated public key. The Short\nID is the path component of the mailbox endpoint. One is derived by hashing the\n33-byte compressed public key encoding with SHA-256, truncating it to\n<a href=\"#64-bit-short-id-length\">8 bytes (64 bits)</a>, and encoding it in\n<a href=\"#uppercase-url\">uppercase</a> using the bech32 character set (like a bech32 string without the HRP, separator and checksum).</p>\n<h5>Receiver fragment parameters</h5>\n<p>This proposal introduces session-specific parameters which the\nreceiver shares encoded in the URI.</p>\n<p>Instead of defining new Bitcoin URI parameters, the session-specific\nparameters are encoded in the <a href=\"https://datatracker.ietf.org/doc/html/rfc3986#section-3.5\">\nfragment</a>\nof the mailbox endpoint URL.</p>\n<p>The <code>#</code> fragment separator character must be <a href=\"https://datatracker.ietf.org/doc/html/rfc3986#section-2.1\">RFC 3986\npercent-encoded</a>\nas <code>%23</code>, because it separates the\nfragment of the mailbox endpoint URL included in the <code>pj</code> parameter, not the\nfragment of the Bitcoin URI.</p>\n<p>These session-specific parameters use a bech32-inspired encoding.\nThe HRP is used as the parameter key, followed by the &#39;1&#39; separator,\nfollowed by the parameter value encoded using the bech32 character set in\n<a href=\"#uppercase-url\">uppercase</a>. No checksum is used. Parameters are separated\nby a <code>-</code> character.</p>\n<p>The following parameters are defined, and must be provided in lexicographical\norder:</p>\n<ul>\n<li><code>EX</code>: specifies a <a href=\"#session-expiration\">session\nexpiration</a> in <a href=\"https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16\">unix\ntime</a>.</li>\n<li><code>OH</code>: encodes an alternate format of the OHTTP Key Configuration of\nthe directory. It consists of a 33-byte compressed public key of the\ndirectory&#39;s OHTTP Gateway, prefixed by the 2-byte Key Identifier. A <a href=\"https://www.ietf.org/rfc/rfc9458.html#section-3.1\">\nRFC 9458 Key\nConfiguration</a>\nis reconstructed by assuming the HPKE KEM ID and Symmetric Algorithms\nare <a href=\"#secp256k1-hybrid-public-key-encryption\">fixed</a>.</li>\n<li><code>RK</code>: encodes the <em>receiver key</em> as a 33-byte compressed public key.\nSenders will initiate HPKE with the receiver using this key.</li>\n</ul>\n<p>For example, a properly encoded endpoint Bitcoin URI looks like this\n<code>bitcoin:tb1q6q6de88mj8qkg0q5lupmpfexwnqjsr4d2gvx2p?amount=0.00666666&amp;pjos=0&amp;pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23EX1WKV8CEC-OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ-RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ6EDSF6AKEWQG758JPS2EV</code></p>\n<p>Until 2026 implementations SHOULD also accept <code>+</code> as a fragment parameter\nseparator and not enforce parameter ordering requirements, for compatibility\nwith the <a href=\"#changelog\">previous version of this document</a>.</p>\n<h3 id=\"sender-original-psbt-messaging\">Sender Original PSBT Messaging</h3>\n<p>The sender constructs the fallback transaction, a typical transaction\nspending funds to the receiver&#39;s address specified in the Payjoin URI.\nThis transaction is serialized as a BIP 174 PSBTv0, satisfying\n<a href=\"#receivers-original-psbt-checklist\">the receiver checklist</a>.</p>\n<p>The Original PSBT MUST:</p>\n<ul>\n<li>Include complete UTXO data.</li>\n<li>Be fully signed.</li>\n<li>Exclude unnecessary fields such as global xpubs or keypath\ninformation.</li>\n<li>Be broadcastable.</li>\n</ul>\n<p>The Original PSBT MAY:</p>\n<ul>\n<li>Include outputs unrelated to the sender-receiver transfer for batching\npurposes.</li>\n</ul>\n<p>This <em>Original PSBT</em> is encoded as base64, followed by the query\nparameter string on a new line containing <a href=\"#optional-sender-parameters\">optional sender\nparameters</a>.</p>\n<p>The sender generates an ephemeral mailbox key. The corresponding public key is\nknown as the <em>reply key</em>, and it is prepended to the base64 plaintext string,\nserialized in compressed form as 33 bytes.</p>\n<p>This plaintext string is encrypted to the receiver key according to <a href=\"https://www.rfc-editor.org/rfc/rfc9180.html#name-encryption-to-a-public-key\">HPKE Base\nmode</a>.\nThe HPKE <code>info</code> string, used for domain separation, is <code>PjV2MsgA</code>. The\nciphertext ensures message secrecy and integrity when passed to the receiver\nusing the mailbox endpoint. The 16-byte authentication tag is appended to the\nciphertext.</p>\n<p>RFC 9180 <a href=\"https://www.rfc-editor.org/rfc/rfc9180.html#section-10\">does not\nspecify</a> the wire format\nencoding of HPKE messages. To construct an HPKE payload, the secp256k1 public\nkey from the DHKEM is encoded using ElligatorSwift in 64 bytes. Note that\nElligatorSwift is only the wire format; when deriving shared secrets, the curve\npoint is re-serialized in uncompressed form.</p>\n<pre><code>PjV2MsgA Byte Representation (7168 bytes total)\n+---------------------------------------------------------------------------------------+\n| ElligatorSwift |                             Ciphertext                               |\n|   (64 bytes)   |                            (7104 bytes)                              |\n|                +-----------------------+---------------------------------+------------+\n|                |       Reply Key       |         Padded Plaintext        |  AEAD Tag  |\n|                |       (33 bytes)      |   (7055 bytes = 7168-64-33-16)  | (16 bytes) |\n+---------------------------------------------------------------------------------------+\n</code></pre>\n<p>The resulting HPKE payload is the body of a POST request to the\nreceiver&#39;s mailbox. This request is then <a href=\"#clientdirectory-interactions\">\nencapsulated</a> according to\nOblivious HTTP to the directory&#39;s OHTTP Gateway. OHTTP serializes the\ninner request as BHTTP, and provides another layer of HPKE encryption,\nbetween the client and directory.</p>\n<p>Upon receipt, the directory&#39;s OHTTP Gateway decapsulates the OHTTP\nrequest and handles the inner POST request at the receiver&#39;s mailbox\nendpoint, which stores the HPKE encrypted payload to be forwarded to the\nreceiver.</p>\n<p>The sender then polls OHTTP encapsulated GET requests to the sender&#39;s\nmailbox endpoint until it receives a response from the directory\ncontaining the receiver&#39;s <em>Proposal PSBT</em>, and proceeds to\n<a href=\"#sender-signing-and-broadcast\">sign and broadcast</a>.\nIt stops polling after expiration.</p>\n<h4 id=\"optional-sender-parameters\">Optional sender parameters</h4>\n<p><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#optional-parameters\">BIP 78&#39;s optional sender parameters</a>\nmay be used in this proposal, but must be included in\nthe body as part of the ciphertext rather than as a query string.</p>\n<p>HPKE binds ciphertexts to application-specific <code>info</code> strings. Because\nof this domain separation, BIP 78&#39;s <code>v</code> parameter is redundant and\nshould be omitted for this proposal.</p>\n<h3 id=\"receiver-proposal-psbt-messaging\">Receiver Proposal PSBT Messaging</h3>\n<p>After sharing the Payjoin URI with the sender, the receiver polls via\nOHTTP encapsulated GET requests to the receiver&#39;s mailbox endpoint. So\nlong as the mailbox contains no message, the directory responds with\nstatus 202 ACCEPTED. Once a mailbox contains a message, the directory\nreturns it in the response body with status 200 OK.</p>\n<p>Upon receiving an encapsulated 200 OK response, the receiver decrypts\nthe payload and checks the <em>Original PSBT</em> therein according to the\n<a href=\"#receivers-original-psbt-checklist\">receiver checklist</a>.</p>\n<p>The receiver then updates the <em>Original PSBT</em> to include new signed\ninputs and outputs, invalidating the sender&#39;s signature(s). The receiver\nmay also adjust the transaction fee. The result, called the <em>Proposal\nPSBT</em>, must satisfy the <a href=\"#senders-proposal-psbt-checklist\">sender checklist</a></p>\n<p>The Proposal PSBT MUST:</p>\n<ul>\n<li>Include complete UTXO data.</li>\n<li>Include all inputs from the Original PSBT.</li>\n<li>Include all outputs which do not belong to the receiver from the\nOriginal PSBT.</li>\n<li>Use a random index if additional inputs or outputs are added.</li>\n</ul>\n<p>The Proposal PSBT sender MAY:</p>\n<ul>\n<li>Add inputs at random indices.</li>\n<li>Add outputs at random indices.</li>\n<li>Remove or modify Original PSBT outputs under the control of the\nreceiver (i.e. not sender change).</li>\n</ul>\n<p>The Proposal PSBT MUST NOT:</p>\n<ul>\n<li>Shuffle the order of inputs or outputs contained in the Original PSBT.</li>\n<li>Decrease the absolute fee of the Original PSBT.</li>\n</ul>\n<p>The receiver encrypts the <em>Proposal PSBT</em> to the sender&#39;s reply key according to\n<a href=\"https://www.rfc-editor.org/rfc/rfc9180.html#name-authentication-using-an-asy\">HPKE Auth\nmode</a>,\nusing the receiver&#39;s key for authentication. The HPKE <code>info</code> string is\n<code>PjV2MsgB</code>. The HPKE wire format is the same as in the <a href=\"#sender-original-psbt-messaging\">sender&#39;s\nmessage</a>.</p>\n<pre><code>PjV2MsgB Byte Representation (7168 bytes total)\n+---------------------------------------------------------------------------------------+\n| ElligatorSwift |                             Ciphertext                               |\n|   (64 bytes)   |                            (7104 bytes)                              |\n|                +---------------------------------------------------------+------------+\n|                |           Padded Plaintext                              |  AEAD Tag  |\n|                |       (7088 bytes = 7168-64-16)                         | (16 bytes) |\n+---------------------------------------------------------------------------------------+\n</code></pre>\n<p>The receiver makes the resulting HPKE payload the body of a POST request to the\nsender&#39;s mailbox whose Short ID is derived from the sender&#39;s reply key. This request is then <a href=\"#clientdirectory-interactions\">\nencapsulated</a> according to\nOblivious HTTP to the directory&#39;s OHTTP Gateway. OHTTP serializes the\ninner request as BHTTP, and provides another layer of HPKE encryption,\nbetween the client and directory.</p>\n<p>The above describes the receiver&#39;s reply path when the sender used\nVersion 2. When the sender used the BIP 78 backwards-compatible path\n(the Original PSBT was a BIP 78 cleartext payload rather than an\nHPKE-encrypted v2 message), the receiver&#39;s response MUST instead follow\n<a href=\"#backwards-compatibility\">Backwards compatibility</a>: the <em>Proposal PSBT</em>\nis not HPKE-encrypted and the request method is <code>PUT</code>.</p>\n<p>Once the receiver makes this request, they wait for either transaction from the\nOriginal PSBT or Proposal PSBT to be broadcast to the Bitcoin network.</p>\n<h4 id=\"receiver-39-s-original-psbt-checklist\">Receiver&#39;s Original PSBT checklist</h4>\n<p>The receiver checklist is the same as <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-checklist\">the BIP 78 receiver\nchecklist</a>.</p>\n<h3 id=\"sender-signing-and-broadcast\">Sender signing and broadcast</h3>\n<p>The sender validates the <em>Proposal PSBT</em> it receives against a\nchecklist. If the checks pass, it may sign and broadcast the resulting\nPayjoin transaction.</p>\n<h4 id=\"sender-39-s-proposal-psbt-checklist\">Sender&#39;s Proposal PSBT checklist</h4>\n<p>This proposal&#39;s sender checklist is the same as <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#senders-payjoin-proposal-checklist\">the BIP 78 sender\nchecklist</a>.</p>\n<h3 id=\"client-directory-interactions\">Client/Directory interactions</h3>\n<p>The Payjoin Directory provides a rendezvous point for senders and\nreceivers to exchange messages. The directory stores Payjoin payloads to\nsupport asynchronous communication. Async Payjoin requests must be\nsubmitted as encapsulated messages to the directory&#39;s OHTTP Gateway.</p>\n<p>The wire format OHTTP request is specified in <a href=\"https://www.ietf.org/rfc/rfc9458.html#name-hpke-encapsulation\">RFC\n9458</a>. HPKE\nrequires the directory&#39;s OHTTP key configuration. The plaintext is a binary\nencoded HTTP request (<a href=\"https://www.rfc-editor.org/rfc/rfc9292.html\">RFC 9292</a>)\nintended for the OHTTP target resource, usually a mailbox endpoint, padded to\n8104 bytes with <a href=\"#random-padding\">random data</a>.</p>\n<pre><code>OHTTP Encapsulated Request Byte Representation (8192 bytes total)\n+--------------+-------------------------+------------------------------------------+\n| OHTTP Header |         HPKE KEM        |               Ciphertext                 |\n|  (7 bytes)   | Uncompressed Public Key |        (8120 bytes = 8192-65-7)          +\n|              |        (65 bytes)       +-----------------------------+------------+\n|              |                         |     Padded BHTTP Request    |  AEAD Tag  |\n|              |                         | (8104 bytes = 8192-65-16-7) | (16 bytes) |\n+--------------+-------------------------+------------------------------------------+\n</code></pre>\n<p>Response encryption uses the Export functionality of the request HPKE context to\nestablish a shared secret, and therefore consists of a 32 byte nonce followed by\nthe AEAD ciphertext and tag.</p>\n<pre><code>OHTTP Encapsulated Response Byte Representation (8192 bytes total)\n+---------------------+------------------------------------------+\n|        Nonce        |               Ciphertext                 |\n|      (32 bytes)     |          (8160 bytes = 8192-32)          +\n|                     +-----------------------------+------------+\n|                     |     Padded BHTTP Response   |  AEAD Tag  |\n|                     |   (8144 bytes = 8192-32-16) | (16 bytes) |\n+---------------------+------------------------------------------+\n</code></pre>\n<p>GET requests on an empty mailbox should block until a message is posted\nor a timeout occurs. The timeout should be 30 seconds because that will\nnot exceed the default timeout for most HTTP clients.</p>\n<p>The directory may optionally accept HTTP/1.1 POST requests without OHTTP\nto mailbox endpoint URLs for backwards compatibility with BIP 78 senders.</p>\n<h4 id=\"ohttp-sequence-diagram\">OHTTP Sequence Diagram</h4>\n<pre><code class=\"language-text\">                                       .-------------------------------------------.\n                                       |              Payjoin Directory            |\n  +--------+        +-----------+      |  +-------------+        +--------------+  |\n  | Client |        | OHTTP     |      |  | OHTTP       |        | HTTP         |  |\n  |        |        | Relay     |      |  | Gateway     |        | Resource     |  |\n  +---+----+        +------+----+      |  +-----+-------+        +------+-------+  |\n      |                    |           `--------|-----------------------|----------&#39;\n      | Relay Request      |                    |                       |\n      | [ + Encapsulated   |                    |                       |\n      |     Request ]      |                    |                       |\n      +-------------------&gt;| Gateway Request    |                       |\n      |                    | [ + Encapsulated   |                       |\n      |                    |     Request ]      |                       |\n      |                    +-------------------&gt;| Request               |\n      |                    |                    +----------------------&gt;|\n      |                    |                    |                       |\n      |                    |                    |              Response |\n      |                    |            Gateway |&lt;----------------------+\n      |                    |           Response |                       |\n      |                    |   [ + Encapsulated |                       |\n      |                    |         Response ] |                       |\n      |              Relay |&lt;-------------------+                       |\n      |           Response |                    |                       |\n      |   [ + Encapsulated |                    |                       |\n      |         Response ] |                    |                       |\n      |&lt;-------------------+                    |                       |\n      |                    |                    |                       |\n</code></pre>\n<h3 id=\"relay-directory-interactions\">Relay/Directory interactions</h3>\n<p>RFC 9458 requires each OHTTP Relay to be configured to forward requests\nto exactly one OHTTP Gateway. This requirement prevents receivers from\nbeing able to choose any directory, and senders from choosing relays\nindependently. Without addressing this limitation, senders would have to\nknow which relays are appropriate to use for each directory, creating a\ntendency for one directory and its affiliated relays to monopolize the\nprotocol.</p>\n<p>In order to allow OHTTP Relays to be used with any directory, a\ndirectory&#39;s OHTTP Gateway may advertise this allowed purpose. This\nadvertisement prevents OHTTP Relays from acting as open internet proxies,\nwhich would otherwise allow anonymized access to arbitrary resources and\nexpose them to denial-of-service attacks, as well as other forms of abuse.\nWhen the directory receives a GET request to the <code>/.well-known/ohttp-gateway</code>\npath with an <code>allowed_purposes</code> query parameter, its response body\nshould contain a magic string in the same format as a TLS ALPN protocol\nlist (a U16BE length encoded list of U8 length encoded strings). The\nmagic string is <code>BIP77 454403bb-9f7b-4385-b31f-acd2dae20b7e</code>, offering\nan unambiguous signal to relays that this OHTTP Gateway will accept\nrequests associated with this purpose from any relay.</p>\n<p>By supporting this <code>allowed_purposes</code> parameter, the directory signals\nto OHTTP Relays that it is willing to handle requests related to BIP 77,\nremoving the RFC 9458&#39;s requirement that relays and\nGateways be configured in a one-to-one relationship.</p>\n<h2 id=\"rationale\">Rationale</h2>\n<h3 id=\"uppercase-url\">Uppercase URL</h3>\n<p>In order to simplify parsing and allow QR encoders to use <a href=\"https://www.rfc-editor.org/rfc/rfc9285.html#name-the-alphabet-used-in-base45\">Alphanumeric\nQR\nmode</a>,\nwhich is more compact than Byte mode, the mailbox endpoint URL,\nincluding the fragment parameters, is encoded in uppercase.</p>\n<p>Unlike Bitcoin URI parameters, which require switching back to Byte\nmode, the use of the URL fragment for session-specific parameters makes\nit possible to stay in Alphanumeric mode.</p>\n<h3 id=\"parameter-ordering\">Parameter Ordering</h3>\n<p>The order of fragment parameters, Bitcoin URI parameters, as well as in the\nsender&#39;s optional parameters have no defined meaning.</p>\n<p>In the BIP 21 URI, the <code>pj</code> parameter mailbox endpoint URL SHOULD be the last\nparameter to avoid QR mode switching.</p>\n<p>Since variations might create a fingerprint for particular wallet software,\nthis document requires that fragment parameters MUST appear in reverse\nlexicographical order.</p>\n<h3 id=\"session-expiration\">Session Expiration</h3>\n<p>The directory may hold a message for an offline Payjoin client until that\nclient comes online. However, the BIP 78 spec <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receiver-does-not-need-to-be-a-full-node\">\nrecommends</a>\nbroadcasting Original PSBTs in the case of an offline counterparty.\nDoing so exposes a naïve, surveillance-vulnerable transaction, which\nPayjoin intends to avoid.</p>\n<p>Because BIP 78 is a synchronous protocol without a standard expiration\nmechanism, and automated receivers are vulnerable to probing attacks,\nBIP 78 encourages receivers to broadcast the Original PSBT after some\nundefined expiration time.</p>\n<p>Because BIP 77 is an asynchronous protocol, it requires an explicit <a href=\"#receiver-fragment-parameters\">\nsession-specific fragment\nparameter</a>, <code>EX</code>, to\ncommunicate this expiration time to the sender.</p>\n<p>There is no way for a sender to prevent a receiver from broadcasting the\nfallback transaction extracted from the Original PSBT before the\nreceiver-specified expiration time.</p>\n<h3 id=\"64-bit-short-id-length\">64-bit Short ID Length</h3>\n<p>64 bits are sufficient to make the probability of experiencing a random\ncollision negligible. As of writing, the UTXO set has ~2^28 elements.\nThis is a very loose upper bound for the number of concurrent (non-spam)\nsessions, for which the probability of a random collision will be less\nthan 1%. The actual number of sessions will of course be (orders of\nmagnitudes) lower given that sessions are short-lived. With ~2^21\nsessions (a loose bound on number of transactions that can be confirmed\nin 24 hours) the probability is less than 1e-6. These figures bound the\nprobability of a collision existing anywhere in the entire set, whereas\nthe probability for an individual session to experience a collision is\n&lt;&lt; 1e-10 in either case.</p>\n<h3 id=\"complete-utxo-data\">Complete UTXO Data</h3>\n<p>Complete UTXO data is required because this information is required for\nsigning and calculating fees for some input types.</p>\n<h3 id=\"http\">HTTP</h3>\n<p>HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core\nto consider an implementation. Unlike a WebSockets protocol, plain HTTP\ncan benefit from metadata protection by using Oblivious HTTP.</p>\n<h3 id=\"oblivious-http\">Oblivious HTTP</h3>\n<p>OHTTP protects sender and receiver IP addresses both from one another\nand from the directory. This makes it more difficult for a directory to\ncorrelate many Payjoin transactions with specific IP addresses.</p>\n<p>OHTTP relays can be run as basic HTTP proxies from wallet providers or\nthird parties.</p>\n<h3 id=\"uniform-payloads\">Uniform Payloads</h3>\n<p>Encapsulated OHTTP payloads seen by the relay and directory, and\nencrypted messages seen by the directory, are constructed to be uniform\nso that these third-party services are unable to distinguish between\nthem.</p>\n<p>Encapsulated OHTTP messages are 8192 bytes long, and begin with a\ncleartext OHTTP header and an uncompressed key which is distinguishable\nfrom random bytes but uniform across different encapsulated requests.</p>\n<p>End-to-end encrypted messages are 7168 bytes long, and should be\nindistinguishable from uniformly random bytes.\n<a href=\"https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#elligatorswift-encoding-of-curve-x-coordinates\">ElligatorSwift as defined in BIP 324</a>\nis used to encode encapsulated HPKE public keys prepended to the HPKE ciphertext\nso that the directory can&#39;t distinguish between key material, the\nciphertext, and randomness. This ensures the two different protocol\nmessages are indistinguishable from each other as well as any protocol\nextensions.</p>\n<p>These padded sizes are sufficient for most PSBTs without exceeding the <a href=\"https://www.geekersdigest.com/max-http-request-header-size-server-comparison/\">\n8KB\nlimit</a>\nof many HTTP/1.1 web servers. 8KB is also too small for image sharing,\nmaking misuse of the directory impractical.</p>\n<h4 id=\"random-padding\">Random Padding</h4>\n<p>The typical <a href=\"https://www.rfc-editor.org/rfc/rfc9292.html#name-padding-and-truncation\">zero padding recommended by the BHTTP\nspecification</a>\nwould make future use of <a href=\"https://github.com/orgs/payjoin/discussions/582\">multi-hop OHTTP inspired by the Sphinx mix\nformat</a> detectable from the\npoint of view of the directory. Random padding is allowed so long as the BHTTP\nencoded request is not truncated.</p>\n<p>By randomly padding OHTTP messages, any future use of such techniques would be\nindistinguishable from clients that only implement standardized OHTTP. Since\nthis would limit a malicious directory&#39;s ability to censor any such requests in\nthe future, and such requests significantly bolster the privacy threat model\nagainst malicious OHTTP relays or traffic analysis by a global passive\nadversary, it is desirable to do so for standard OHTTP requests as well.</p>\n<h3 id=\"secp256k1-hybrid-public-key-encryption\">Secp256k1 Hybrid Public Key Encryption</h3>\n<p><a href=\"https://www.rfc-editor.org/rfc/rfc9180.html\">RFC 9180 Hybrid Public Key\nEncryption</a>\n(HPKE) is a modern IETF standard for secure\nmessage exchange without TLS, since TLS is not available in Bitcoin Core.</p>\n<p>This proposal uses <code>DHKEM(Secp256k1, HKDF-SHA256)</code> and\n<code>ChaCha20Poly1305</code> AEAD for both OHTTP encapsulation and for end-to-end\nencryption between the sender and receiver.</p>\n<p>The receiver transmits its receiver key in <a href=\"#receiver-fragment-parameters\">receiver fragment\nparameters</a>. The sender shares\nits reply key along with the Original PSBT. These keys are ephemeral and\nmust only be used for a single Payjoin Session.</p>\n<h4 id=\"secp256k1-based-dhkem\">Secp256k1-based DHKEM</h4>\n<p><a href=\"https://www.ietf.org/archive/id/draft-wahby-cfrg-hpke-kem-secp256k1-01.html\">Secp256k1-based DHKEM for\nHPKE</a>\nis most appropriate because of secp256k1&#39;s availability in bitcoin\ncontexts.</p>\n<h4 id=\"chacha20poly1305-aead\">ChaCha20Poly1305 AEAD</h4>\n<p>This authenticated encryption with additional data <a href=\"https://en.wikipedia.org/wiki/ChaCha20-Poly1305\">\nalgorithm</a>\nis standardized in <a href=\"https://www.rfc-editor.org/rfc/rfc8439\">RFC\n8439</a> and has high\nperformance. ChaCha20Poly1305 AEAD has been implemented <a href=\"https://github.com/bitcoin/bitcoin/pull/15649\">in Bitcoin\nCore</a> for <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki\">\nBIP 324 Encrypted\nTransport</a>\nas well. This has widespread support in browsers and common\ncryptographic libraries. AES-GCM is more widespread but slower without\nhardware support and not typically already a dependency in bitcoin software.</p>\n<h4 id=\"hkdf-sha256\">HKDF-SHA256</h4>\n<p>SHA-256 is necessarily available in bitcoin contexts.</p>\n<h2 id=\"attack-vectors\">Attack vectors</h2>\n<p>In addition to the attack vectors and mitigations in\n<a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#attack-vectors\">BIP 78</a>,\nthis proposal has the following attack vectors.</p>\n<h3 id=\"directory-denial-of-service\">Directory Denial of Service</h3>\n<p>Since each mailbox stores arbitrary encrypted payloads, directories are\nvulnerable to flooding. To mitigate such denial of service attacks,\ndirectory operators may respond with <code>401</code> unauthorized unless an\nauthorization token is provided. Authorization tokens must be unlinkable\nto preserve client privacy. A specific unlinkable authorization token\nmechanism is out of the scope of this proposal.</p>\n<h3 id=\"network-privacy\">Network privacy</h3>\n<p>Oblivious HTTP must be used to protect the IP addresses of both sender\nand receiver from the directory. This requires an OHTTP Key\nConfiguration to be shared in the Payjoin URI and for the directory to\nsupport Oblivious HTTP.</p>\n<p>Unlike BIP 78 implementations, sender and receiver clients will only see\nthe IP address of the directory and not that of the client they are\ninteracting with.</p>\n<p>Senders that submit requests directly to the directory, without using\nan OHTTP Relay, may reveal their IP address to the receiver since that\nreceiver also specifies the directory.</p>\n<h2 id=\"backwards-compatibility\">Backwards compatibility</h2>\n<p>Senders not supporting Payjoin will just ignore the <code>pj</code> parameter and\nproceed to typical address-based transaction flows.</p>\n<p>All Payjoin versions use <a href=\"#payjoin-uri\">Bitcoin URIs</a>.\nReceivers may choose to accept BIP 78 payloads at their discretion.</p>\n<p>A BIP 78 sender posts their request to the directory, which stores\nand forwards it to the BIP 77 receiver. A backwards-compatible\nreceiver proceeds with the BIP 78 checks if the encapsulated response\nbody is UTF-8 plaintext, signifying BIP 78. In order to service the\nrequest, a BIP 78 response must be returned to the sender within 30\nseconds or else the directory should respond with an <code>unavailable</code> JSON\nerror code as <a href=\"https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors\">defined in BIP\n78</a>.</p>\n<p>When responding to a BIP 78 sender, the receiver MUST NOT HPKE-encrypt\nthe <em>Proposal PSBT</em>. The receiver MUST send the <em>Proposal PSBT</em> as the\nbody of a PUT request, with the body being the base64-encoded PSBT,\nencoded as ASCII bytes. The target mailbox endpoint MUST be the\nreceiver&#39;s own mailbox (the same mailbox at which the sender posted the\n<em>Original PSBT</em>), because a BIP 78 sender provides no reply key from which\na sender-side reply mailbox could be derived. The PUT request is then\nOHTTP-encapsulated to the directory&#39;s OHTTP Gateway as for any other\nPayjoin Directory interaction.</p>\n<h2 id=\"reference-implementation\">Reference implementation</h2>\n<p>A production reference implementation client can be found at\n<a href=\"https://crates.io/crates/payjoin-cli\">https://crates.io/crates/payjoin-cli</a>. Source code for the clients, the\ndirectory, and development kit may be found here:\n<a href=\"https://github.com/payjoin/rust-payjoin\">https://github.com/payjoin/rust-payjoin</a>. Source code for an Oblivious\nHTTP relay implementation may be found here:\n<a href=\"https://github.com/payjoin/ohttp-relay\">https://github.com/payjoin/ohttp-relay</a>.</p>\n<h2 id=\"changelog\">Changelog</h2>\n<ul>\n<li>0.2.0 2025-07-08<ul>\n<li>Change fragment parameter delimiter from <code>+</code> to <code>-</code> to improve\ncompatibility with generic URI parsing libraries, and order them\nlexicographically. <code>+</code> can cause issues due to a common convention (not\nspecified in RFC 3986, but in RFC 1866, in relation to HTML form\nsubmission and query parameters) of interpreting <code>+</code> as <code> </code> when decoding\nURIs.</li>\n</ul>\n</li>\n<li>0.1.0 2025-05-28<ul>\n<li>First merged Draft version of BIP 77</li>\n</ul>\n</li>\n</ul>\n","toc":[{"id":"copyright","title":"Copyright","level":2},{"id":"abstract","title":"Abstract","level":2},{"id":"motivation","title":"Motivation","level":2},{"id":"overview","title":"Overview","level":2},{"id":"async-payjoin-directory-mediated-sequence-diagram","title":"Async Payjoin Directory Mediated Sequence Diagram","level":3},{"id":"specification","title":"Specification","level":2},{"id":"ohttp-bootstrapping","title":"OHTTP Bootstrapping","level":3},{"id":"session-initiation","title":"Session Initiation","level":3},{"id":"payjoin-uri","title":"Payjoin URI","level":4},{"id":"sender-original-psbt-messaging","title":"Sender Original PSBT Messaging","level":3},{"id":"optional-sender-parameters","title":"Optional sender parameters","level":4},{"id":"receiver-proposal-psbt-messaging","title":"Receiver Proposal PSBT Messaging","level":3},{"id":"receiver-39-s-original-psbt-checklist","title":"Receiver&#39;s Original PSBT checklist","level":4},{"id":"sender-signing-and-broadcast","title":"Sender signing and broadcast","level":3},{"id":"sender-39-s-proposal-psbt-checklist","title":"Sender&#39;s Proposal PSBT checklist","level":4},{"id":"client-directory-interactions","title":"Client/Directory interactions","level":3},{"id":"ohttp-sequence-diagram","title":"OHTTP Sequence Diagram","level":4},{"id":"relay-directory-interactions","title":"Relay/Directory interactions","level":3},{"id":"rationale","title":"Rationale","level":2},{"id":"uppercase-url","title":"Uppercase URL","level":3},{"id":"parameter-ordering","title":"Parameter Ordering","level":3},{"id":"session-expiration","title":"Session Expiration","level":3},{"id":"64-bit-short-id-length","title":"64-bit Short ID Length","level":3},{"id":"complete-utxo-data","title":"Complete UTXO Data","level":3},{"id":"http","title":"HTTP","level":3},{"id":"oblivious-http","title":"Oblivious HTTP","level":3},{"id":"uniform-payloads","title":"Uniform Payloads","level":3},{"id":"random-padding","title":"Random Padding","level":4},{"id":"secp256k1-hybrid-public-key-encryption","title":"Secp256k1 Hybrid Public Key Encryption","level":3},{"id":"secp256k1-based-dhkem","title":"Secp256k1-based DHKEM","level":4},{"id":"chacha20poly1305-aead","title":"ChaCha20Poly1305 AEAD","level":4},{"id":"hkdf-sha256","title":"HKDF-SHA256","level":4},{"id":"attack-vectors","title":"Attack vectors","level":2},{"id":"directory-denial-of-service","title":"Directory Denial of Service","level":3},{"id":"network-privacy","title":"Network privacy","level":3},{"id":"backwards-compatibility","title":"Backwards compatibility","level":2},{"id":"reference-implementation","title":"Reference implementation","level":2},{"id":"changelog","title":"Changelog","level":2}],"history":{"totalCommits":14,"firstCommit":"2025-05-28T14:49:12-04:00","lastUpdated":"2026-06-01T16:13:54+08:00","events":[{"sha":"9997e005765d516b40a6646317ff78b5175f630b","date":"2026-06-01T16:13:54+08:00","author":"DanGould","message":"BIP 77: Specify v1-fallback response mechanism","url":"https://github.com/bitcoin/bips/commit/9997e005765d516b40a6646317ff78b5175f630b","kind":"edit"},{"sha":"1c4fe8dfea1774a8e79c7c42460782573330f13f","date":"2026-01-14T04:50:52+08:00","author":"Dan Gould","message":"BIP77: Change sequence diagrams to text format (#2064)","url":"https://github.com/bitcoin/bips/commit/1c4fe8dfea1774a8e79c7c42460782573330f13f","kind":"edit"},{"sha":"4486d6de91c9b46c256fec215f13fac818410a37","date":"2025-12-15T16:48:19-08:00","author":"Murch","message":"process: Backfill missing Version headers","url":"https://github.com/bitcoin/bips/commit/4486d6de91c9b46c256fec215f13fac818410a37","kind":"edit"},{"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":"01352f7f40cb7f61d0aa177341f8804de2f8fed9","date":"2025-04-11T20:07:37-07:00","author":"Murch","message":"process: Post-History ↦ Discussion","url":"https://github.com/bitcoin/bips/commit/01352f7f40cb7f61d0aa177341f8804de2f8fed9","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":"c83aeb8d28e5faa8d8bb85bdb133536b813c4ce6","date":"2025-07-21T21:11:36+02:00","author":"crStiv","message":"Update bip-0077.md","url":"https://github.com/bitcoin/bips/commit/c83aeb8d28e5faa8d8bb85bdb133536b813c4ce6","kind":"edit"},{"sha":"cd19d89e58b8c9b84f18efb5659220d4755fff0b","date":"2025-07-10T02:24:55+02:00","author":"Yuval Kogman","message":"scripted-diff: fix BIP 2 field order violations","url":"https://github.com/bitcoin/bips/commit/cd19d89e58b8c9b84f18efb5659220d4755fff0b","kind":"edit"},{"sha":"8b83c34949e53805fa04cf44aa88a17650df6b29","date":"2025-07-03T16:25:36+02:00","author":"Yuval Kogman","message":"Specify lexicographical order for fragment params","url":"https://github.com/bitcoin/bips/commit/8b83c34949e53805fa04cf44aa88a17650df6b29","kind":"edit"},{"sha":"43f9688600c7bcd79eabc5cca15c54e51626b1dc","date":"2025-07-03T16:24:02+02:00","author":"Yuval Kogman","message":"Separate fragment params with `-` instead of `+`","url":"https://github.com/bitcoin/bips/commit/43f9688600c7bcd79eabc5cca15c54e51626b1dc","kind":"edit"},{"sha":"88a1ae5782390be7417ccc873018eae56299a486","date":"2025-05-30T15:31:46-04:00","author":"Brandon Lucas","message":"BIP77: remove duplicate \"the\"","url":"https://github.com/bitcoin/bips/commit/88a1ae5782390be7417ccc873018eae56299a486","kind":"edit"},{"sha":"72af87fc72999e3f0a26a06e6e0a7f3134236337","date":"2025-05-28T11:56:35-07:00","author":"Jon Atack","message":"BIP77: remove redundant sentence line (#1858)","url":"https://github.com/bitcoin/bips/commit/72af87fc72999e3f0a26a06e6e0a7f3134236337","kind":"edit"},{"sha":"ee587c5d2f0e66de0811649bc0b59fb9fc9f0635","date":"2025-05-28T14:49:12-04:00","author":"Dan Gould","message":"BIP 77: Async Payjoin (#1483)","url":"https://github.com/bitcoin/bips/commit/ee587c5d2f0e66de0811649bc0b59fb9fc9f0635","kind":"edit"}]}}