The “pay:” URL scheme

When you buy something in an online store, the payment is usually by credit card, and it involves going through a number of forms, different for every online store, which then redirect to another site with another form, and sometimes after that it redirects to a form on your own bank's site, where you have to enter a code that you get by SMS. It's complicated, cumbersome, error prone, and it usually doesn't work without JavaScript and cookies, so in my case it usually doesn't work at all.

Compare that to paying in a real shop. There is no such hassle, you're not asked so many questions, and it is the same, simple routine every time.

So what is actually required to make a payment?

  1. The amount to pay, including the currency.
  2. The bank account of the seller.
  3. The order number.
  4. Not strictly required, but useful (see below): the name of the seller
  5. Not strictly required either: the URL of a page on the seller's site where you can see the status of the transaction.

So let's code that up in a URL. Say you have to pay 57.65 Euro to Dupont & Cie, whose IBAN is FR76 4100 4133 7601 0505 1161 123, for order number ANM11-1210:


For readability, we could allow optional longer field names and dots in the account number (like in the tel-scheme for phone numbers):


Now put that in a link in a Web page (<a href="pay:...">Pay</a>). When you click it, it opens whatever you have configured as your payment system: It may open a separate application, just like a “mailto:” link opens a mailer or a “magnet:” link opens a Bittorrent program; or it may open a browser on an appropriate page on your bank's Web site. Whatever it does, it will be the same interface for every payment you make, so there will be no more confusion about what you're supposed to do. You just check that the amount is correct and press whatever buttons your payment system requires to make your bank transfer the money.

If you pay a certain seller for the first time, your payment system may not yet know the name that belongs to the account number and then the name field in the URL is useful. Especially if you are doing multiple payments at the same time, seeing the amount and the name of the receiver is good.

The page that had the pay link could have a another link to a status page, where you can see if the seller has received your payment yet and has shipped your goods. Or the page can itself be a status page and just tell you to reload it. Or the pay URL could include the URL of a status page, so that your payment application can send you there after the transaction is done (and also every time you open the payment system to check on your past transactions).

Of course, if you click on a pay link twice, your payment system should notice that and refuse to transfer any money to the same account for the same order number. (It's probably best if not only your payment application does that check, but also your bank, just in case you happen to click the same pay link on a different computer, which doesn't have a memory of the earlier transaction.)

Informing the seller of the payment

Possible problem: how will the seller know that you have paid? When you tell your bank to transfer money, the bank will first deduct the money from your account and put it on the bank's own account for 24 hours (so the bank can get some interest on it) and only then transfer it to the seller's account. So the seller won't know immediately that you have paid and won't send you the goods.

What's needed, it seems, is that the buyer's bank sends a notice to the seller's bank that some money is coming. If the seller's bank trusts the buyer's bank, it will show the notice to the seller, who (if he, too, trusts the buyer's bank) will release the goods.

Anonymous money instead of bank transfers

Even better could be a system that didn't involve the buyer's and the seller's bank at all. If the buyer possesses virtual “coins” drawn on some bank that the buyer and the seller both trust, e.g., some national bank, then the seller can put his e-mail address instead of his bank account in the pay URL and the buyer can then send some coins to that address. (The buyer should of course encrypt the e-mail with the seller's public key, to avoid that the coins are stolen). The seller doesn't have to poll his bank to see if he received payment yet. He just has to wait for the e-mail with the coins and then exchange the coins for new ones at the bank that issued them. (Instead of an e-mail address, an FTP or HTTP address to PUT/POST the coins to also works.)

MIME type vs URL scheme

[Added on 29 July 2014] A URL shouldn't be too long. For more flexibility, the data can be put in a file that the URL then points to. In that case, the URL scheme could be anything that allows file transfers, including HTTP. And it is not the URL scheme, but the file's Internet Media Type (a.k.a. MIME type) that tells the browser what to do with it.

There are formats like that, e.g., OFX (an XML-based format), but none that are standards. And none so far have Media Types defined for them.

Invoices by e-mail and asynchronous transactions

[Added on 29 July 2014] A “pay” URL is in fact a very small, machine readable invoice. If the data is in a file with the proper Media Type, then that file is the invoice.

The URL or the file don't have to be on a Web page, they can be sent in an e-mail, printed on paper as a QR code, etc. Thus it is possible to send invoices to people who aren't online. And people who bought something online can decide to store away the invoice and pay it later.

If your payment software also allows working offline, you can do your payments and bookkeeping while on a plane, e.g.. The software will prepare a batch of transactions to send off the next time you're online.

The “BezahlCode” or “bank:” URL scheme

[Added on 20 December 2016] Christian Weiske informed me that there is actually a “bank:” URL scheme in use by some shops in Germany. See my article on the BezahlCode.

Bert Bos <bert at>
Created: 8 October 2012