
Full recording. Plays from youtube-nocookie.com. Watch on YouTube
TL;DR
- PayJoin v2 needs no server of your own: a mailbox directory holds encrypted messages and a relay hides your IP address.
- Neither server ever touches your bitcoin or can read the payment. Run by two different parties, neither can link sender and receiver.
- Live tests mostly failed: silent fallbacks to normal payments, v1/v2 mismatches, and no clear error messages.
- The protocol is simple. The wallet experience is the work left to do, and that is where new contributors come in.
Highlights
1How PayJoin v2 works
The hard part is not the transaction, it’s the conversation. In a PayJoin, the receiver adds one of their own coins to your payment, so the sender and receiver have to swap a partly signed transaction (a PSBT) before it is sent. In v1 the receiver had to run a web server that was always online. Version 2 moves that job to two shared servers that anyone can run.
PayJoin v2, the message path
The reply goes back the same way. The receiver can be offline when you pay. Their wallet picks up the mailbox later, and the payment finishes then.
Everything is in the PayJoin link. A v2 receive link looks like a normal Bitcoin address with a long tail. That tail carries three things:
Inside a PayJoin v2 link
directoryWhich mailbox server to use
mailbox IDLike an email address for this one payment
public keyThe receiver’s key. The sender uses it to encrypt the PSBT, so the directory only sees a locked blob
What do you have to trust? Very little. The servers never touch bitcoin and can’t read the payment. The directory could still see which IP addresses use the same mailbox, so the relay sits in front of it, a bit like Tor. If one company ran both the relay and the directory, it could link the IPs again, so they should be run by different people. You can see which ones your wallet uses under PayJoin in the advanced settings of Cake Wallet or Bull Bitcoin.
2Testing it live
The protocol works. The wallets don’t, yet. One incoming PayJoin from an earlier session showed up on mempool.space as 2 inputs and 2 outputs, exactly as it should. Then we tried to send more on the call, and almost every attempt hit a different wall:
What we ran into
Also: Bull Bitcoin asked for a minimum of about 10,000 sats, which isn’t in the PayJoin spec, and some wallets just spin with no error at all.
“Show me the error. Show me what I can do. Tell me if it worked.”
A participant who has tried PayJoin more than ten times, on what wallets need most
Key takeaways
Use it every time, not once in a while. PayJoin looks like any normal payment, unlike a CoinJoin, which is easy to spot and often gets flagged. The idea shared on the call: if even 5 to 10% of payments were PayJoins, chain analysis could no longer trust its “all inputs belong to one person” guess for any payment.
Know the trade-off. The person who receives your PayJoin learns a little about your coins, and you about theirs. It’s similar to what happens when you combine coins in one transaction anyway.
Where to start contributing. Build and run rust-payjoin first. Make a PayJoin, break a test. Then pick one of the open pull requests and review it. It can take days, and feeling lost is normal. Bindings for other languages and the new BTCPay Server plugin both need help, and the wallet issues from the live test are worth reporting.
Quiz recap
Resources shared
Reading
- BIP 77: Async PayJoin (v2): the mailbox directory and relay design covered in this session
- BIP 78: PayJoin (v1): the older version, where the receiver runs a server that is always online
- RFC 9458: Oblivious HTTP: the standard behind the OHTTP relay that hides your IP from the directory
- RFC 9180: HPKE: hybrid public key encryption, used to lock the PSBT so only the receiver can read it
Tools
- rust-payjoin: the core PayJoin library, now with the OHTTP relay inside it; FFI bindings for other languages need testing and help
- PayJoin on GitHub: all PayJoin projects, including the new BTCPay Server plugin (alpha)
- payjoin.org: docs and the list of wallets that support PayJoin
- Cake Wallet issues: search here first, then open an issue if a PayJoin bug isn't reported yet
- mempool.space: used live to check whether a payment really was a PayJoin (2 inputs, 2 outputs)
- Blooket: the quiz Razor ran on the call (not private, so use any name)
Wallets
- Cake Wallet: PayJoin v2; quietly sends a normal payment if the PayJoin fails
- Bull Bitcoin: PayJoin v2; the live test showed a v1 error and a minimum amount
- Sparrow: sends PayJoin v1 only, so it can't pay a v2-only wallet
- BTCPay Server: receives PayJoin v1 for merchants; a v2 plugin is in alpha
Code Orange
- PayJoin part 1, 6 October: why privacy matters and how PayJoin fools chain analysis
- Privacy Developer Track: every 1st and 3rd Tuesday, 07:00 UTC · 15:00 UTC+8
Coming next: Razor is building hands-on PayJoin labs (make a PayJoin, talk to the relay, talk to the directory, find and fix a bug) and a quiz leaderboard on GitHub that will also count code reviews and pull requests. Ideas from the call: invite someone from the PayJoin team as a guest speaker.
These notes are also on GitHub: code-orange-dev/session-notes. Free to share and reuse (CC0).