Why payment pointers are URLs


It was a great start to the week last week when I logged on to Twitter to find that Fynbos had received a mention from Simon Taylor in his latest Fintech Brainfood newsletter. Even better was reading the newsletter and seeing that Simon seems to really understand the big picture of what we’re building with payment pointers, which is incredible validation from someone that is so widely respected in the industry.

I’ve been a follower of Simon’s since he was at Barclays when he was a lonely voice from inside “the big banks” that saw the potential of blockchain technology. So it was an even bigger (and better) surprise to read that the entirety of his next newsletter was dedicated to exploring a “universal, human-readable address for money”.

Simon clearly shares the vision we do, where users don’t have to deal with complexities like IBANs, bank accounts, routing numbers, or even card numbers (and expiry dates and CVVs) but instead have a simple way to address counter-parties in a transaction.

What was interesting to read was that Simon’s passion to solve this was part of the reason he got into payments and fintech in the first place, or in his own words it was his “raw enthusiasm for what Twitter could become if it added payments”.

Simon’s post is about how an existing handle (in his case, a Twitter handle as opposed to a payment pointer) could be the “universal pointer to payments”. He’s mostly thinking about what Twitter could do to leverage its own universal address as a means to get into payments (as Elon Musk has suggested he wants to do) as opposed to designing the perfect payment pointer.

In our version of this vision, payment pointers are URLs and therefor intentionally not an address controlled by a single organisation like Twitter, but Simon still nails many of the benefits of the universal address model such as:

  • an abstraction over various rails and payment methods

  • a single address for anyone to send payments to

  • a single payment instrument to make payments anywhere

Using a URL rather than a proprietary handle has a number of advantages and I considered writing a long blog post here going into the details, but a lot of what Simon said reminded me that I’d already covered the same ground in my recent talk at the Interledger Summit in New Orleans.

So instead, I’ve provided a summary of some of the benefits of using a URL as a payment pointer and the challenges with overloading other identifiers like Twitter handles, mobile numbers or email addresses but I’d really recommend watching the video of my talk to fully appreciate why payment pointers are the ideal “human-readable address for money”.

The video is also embedded at the end.

The universal symbol for money: $

While it’s not the only currency symbol available, few can disagree that the dollar symbol $ is the most widely recognised symbol for money.

Payment pointers start with a dollar symbol (in place of the normal https:// prefix) so that they are:

  1. Easy to recognise as a payment pointer, and distinct from other URLs that are not payment pointers.

  2. Easy to distinguish from other addresses like Twitter handles, email addresses, Mastodon addresses etc.

  3. Simple to read and transcribe (notice how browsers have also stopped showing the “https://” prefix in their address bars to make those easier to read).

  4. Easy to deterministically translate into a URL to be used by software (just replace the “$” with “https://”).

The only currency symbol in the ASCII table is the dollar but extended ASCII has the pound, yen and sometimes the euro (depending on which standard you’re following). The dollar symbol is the only currency symbol allowed in a URI as defined by RFC 3986. There are currencies that use regular letters as symbols but using something like a capital “R” (the symbol for South African Rands) wouldn’t make payment pointers distinctive.

Discovery and APIs

One of the main reasons payment pointers don’t overload an existing identifier (like an email address, mobile number or Twitter handle) is to facilitate service discovery without needing to attach additional context or use a central registry.

It’s very common to use a mobile number or email address as an alias or proxy for an account in many existing instant payment systems like Zelle, UPI, Mpesa etc. But, if I give you my email address, for example, and ask you to send money to it, where do you start?

What service do you use to determine what account my email address maps to or what payment method to use? If it’s Zelle, for example, then I need to share that information with you too which makes having a single universal address kind of redundant.

The whole system also breaks down if you’re in another country or want to pay me over something other than Zelle. Normally the registry for account proxy addresses is tightly coupled to a payment scheme so this defeats the purpose of having a universal address that abstracts this away and maps to multiple schemes.

In the case of using a Twitter handle, service discovery is easier, the service is just Twitter. But by using Twitter handles we hand over all governance of that address to Twitter. The same applies for any other address where the address-space is controlled by the issuer of the addresses.

If the rights of users to post on Twitter can be revoked at the whim of a random moderator (or owner) I’d be loathe to trust Twitter to be the issuer of my universal payment address.

As a URL, my payment pointers are not only identifiers for my wallet but are also the addresses for an API endpoint that can be used to interact with my wallet. The identifier is also the service entry-point. This makes the need to discover the service from the identifier redundant.

Anyone that has been involved in protocol design work will know this solves a major challenge when designing a robust and yet decentralised system that doesn’t rely on a registry. A lot of the work in the last 10 years on decentralised systems has grappled with this and most solutions tend to get complex and have many layers of indirection.

Distributed Identifiers (DIDs) resolve to a DID document that lists a service endpoint (among other things). But the method of resolving the document and the protocol that is used to address the service endpoint could be any one of hundreds of combinations. This makes the system very flexible but also very challenging to build an ecosystem of implementations that are interoperable.


The solution to decentralising payment pointers is using namespaces so that anyone that owns a namespace can issue a payment pointer in their namespace. Using domain names as the namespaces for payment pointers has many advantages:

  1. DNS is a mature and well entrenched technology that has served the Web well for decades.

  2. Domain names are available to anyone and there are hundreds of domains to choose from with different governance structures and properties to suit different needs.

  3. The infrastructure around DNS is comprehensive including Public Key Infrastructure that uses domain names as subject names.

Just like email addresses, end-users can choose to get their own domains and issue their own payment pointers, or they can simply use the domain they get from their payment pointer issuer. This is the equivalent of just using an @gmail.com email address vs wiring your email service to your own custom domain.

As soon as we’re live with our Fynbos wallet my own payment pointer will be $fynbos.me/adrian but we plan to support custom domains soon after launch so I could use my Fynbos wallet with a payment pointer like $adrian.hopebailie.com. It’s easy to see how this would appeal to businesses that can use their existing domains instead of fighting for appropriate handles on Twitter.

If anyone knows how to get the Twitter handle @fynbos for us I’d really appreciate it. It seems to be a mostly abandoned account and as a result we have had to use @fynbosdev.

Users should also be able to have multiple payment pointers from different namespaces that all point to the same wallet (remember HTTP does support redirects natively). So, if Twitter supported payment pointers I could also make my Twitter handle a payment pointer ($twitter.com/ahopebailie). Smart user interfaces would allow users to enter a Twitter handle and simply convert it to a payment pointer under the hood with the implicit namespace of “twitter.com”.

Finally, we can’t completely ignore what’s happening in the Web 3.0 world where projects like ENS have launched new top-level domain names backed by blockchains that don’t even require root servers. That’s pretty extreme decentralisation, and in my opinion more than most people will ever need, but by using domain names as the namespace for payment pointers we future proof them to also support ENS names and similar namespaces one day if this is what users want.

The UNCDF, driven by Arunjay Katakam, have done some really interesting research that touches on the use of payment proxies. They have come to similar conclusions around the value of universal payment addresses but they are advocating for mobile phone numbers and Legal Entity Identifiers (LEIs) which, as I’ve pointed out are not ideal for this purpose. I’m working on changing Arunjay’s mind.


Using URLs means that the first thing we do with a payment pointer is make an HTTP request to that URL. The best thing about HTTP is how flexible it is as a protocol for interacting with resources (like wallets) and we can take advantage of that in how we design the protocols underpinning payment pointers.

  1. Content-Type negotiation

HTTP allows a client (a browser, or another service running on a computer somewhere) to specify the type of content it wants in response to a request. The same request, a GET request to the payment pointer for example, could return a Web page in the form of HTML or a machine readable response in the form of JSON data.

This means that if you pass your payment pointer to a wallet it might request the data about that payment pointer and begin communicating with your wallet via APIs, but if you visited that same payment pointer URL in a browser (maybe because you scanned it as a QR code on a checkout page) you’d get back a Web page. In the case of the Web page you might get details on how to send a payment to that payment pointer or whatever the service behind the payment pointer decides.

If Twitter supported payment pointers then visiting my payment pointer from Twitter ($twitter.com/ahopebailie) would simply land you on my profile (and maybe you’d see an option to send me money) but if a wallet that supported payment pointers queried that same URL it might get back something like this:

  "publicName": "Adrian Hope-Bailie",
  "paymentMethods": [
  "currencies": ["USD", "EUR", "ZAR", "BTC"]
  1. HTTP Verbs

The other great feature of HTTP is verbs.

If you just want to query some public data about a payment pointer then you can make a GET request to the URL and you might get a response like the one above.

But, if you want to start a transaction with that wallet then you’re likely wanting to begin negotiating with the service entry-point, so instead you would send a POST request including the details of what you want to do.

Or, you might be wanting to query the meta data about the service entry-point (not the payment pointer itself) such as which aspects of the protocol it supports (the key types, signature algorithms etc). In this case you would send an OPTIONS request.

Having all of these options available for interaction with the same URL makes the use of payment pointers extremely efficient.

Payment pointers are hosted by servers that follow the Grant Negotiation and Authorization Protocol (GNAP) which defines the behaviour for the POST and OPTIONS operations. Digging into the details of GNAP and how we’re using it with payment pointers is the subject of another post.

At Fynbos we’re exploring the various ways we can use payment pointers for different use cases that are appropriate for a digital wallet. Our focus is on payments but it’s clear this could expand to other interesting domains like identity and verified credentials.

In his newsletter, Simon set out to paint a picture of what Twitter could do if they leveraged their proprietary handles as addresses for payment. We’re taking that idea further and demonstrating what any bank, wallet, or any account provider could do if they leveraged the namespace they already own (their domain name) to issue a digital native payment instrument that could be the universal human-readable address for payments.

There’s a lot to still figure out and we’re excited to work with partners like Sardine and smart people like Simon to do it. Our mission is to build the better way to pay and I’ll definitely be reaching out to Simon to see if we can dig into this further together. If you're keen to get involved, get in touch.

Finally, if you want to start experimenting with payment pointers, either as a user or an issuer, get on our waitlist and get your own payment pointer, or get in touch and we can help you start issuing payment pointers for your users.

Once you're on the waitlist, sit back, relax, and enjoy the video below while we finish polishing up the wallet for you. We'll be in touch soon.