The amount option is leaving a slightly bitter taste in my mouth.
• It allows commas, which will just be stripped on execution. This feels like it’s just inviting errors unnecessarily, especially given that some parts of the world use comma (,) as their decimal separator and full stop (.) for grouping, rather than the other way round. I see no compelling reason for allowing grouping at all.
• “The 'unit' value MUST be smaller than 2^53. If present, the 'fraction' MUST consist of no more than 8 decimal digits.” Both of these feel a mite surprising, and the combination of them far more surprising. The 2⁵³ limit is doubtless to allow it to be safely stored in a 64-bit floating point number, specifically for JavaScript’s sake; but (dealing with this part first) do you know how small 2⁵³ is? 9 quadrillion. That’s honestly not that large. I’ve handled a 100 trillion dollar note, and that’s hardly the highest any currency has ever gone. (Admittedly, the sorts of currencies where this is happening probably have limited use for a payto: URI scheme at the time.) But anyway, skipping onto the second part, a fraction of up to eight digits. Skipping over the apparent arbitrariness of the number (which happens to match Bitcoin’s division), if you’ve made concession to treat the unit as a Number, what about the fraction? If you wanted to retain eight decimal places of significance, you’d be limiting your unit to 2⁵³ ÷ 10⁸, about 90 million, which is obviously too low, so you clearly can’t be meant to be representing the whole thing as a Number, so why that restriction on the unit? So yeah, both of these limits simply feel weird to me.
But other than these quibbles, I say: finally! I’m really glad about this and hope it gets adopted by banking apps and the likes quickly, and added to the HTML spec’s safelisted schemes (https://html.spec.whatwg.org/#safelisted-scheme) so that banks’ web apps can also navigator.registerProtocolHandler("payto", "https://bank.example/payto-handler/%s") soon. And also that Australian banks either register some way of addressing their accounts as a payto payment target type, or adopt IBAN.
Omitting a comma turns an amount with Euro Cents to 100 times the amount here in Germany. I can both see this comma/dot problem be missed in development and can also imagine such a payment go through, as a few digit amount times one hundred still gives an amount that people can have in their bank accounts. Users clicking through confirmation dialogs and dismissing wrong information as 'computer problems' is not an unheard-of problem either.
This is really inviting trouble - without good reason? - as a payment 'API' having to deal with how a number was displayed to a user seems out of scope for it.
Seriously, not to get too down on the author, but whoever wrote this was way out of touch with what a decent standard should look and act like. So many blatant flaws like this.
This reminds me of a bug I happened to come across with a cheap offshore company I had to deal with a while back (well, a very expensive consulting company that used a very cheap offshore company for development). We were dealing solely with Pound Sterling (100 pence make a pound). As part of the API requirements, they were asked to solely deal with pence in integers. They ignored the requirements and used pounds in floats.
This caused rounding errors here and there. We spotted the problem as soon as we heard about the rounding errors, and asked them to correct it. Later on, our customer asked us why the items that cost £1.85 were being charged correctly, but the items that cost £1.90 were being charged at 19p.
Turns out that rather than doing anything sensible, they took the float, converted it to a string, stripped out the period, then converted the string to an integer. So £1.85 became "1.85", then "185", then 185p, but £1.90 became "1.9", then "19", then 19p.
They managed to put this into production before we had a chance to see it. Yes, it was a dysfunctional project. But there’s lots of them out there. If you leave a footgun like this lying around, there’s no end of companies that will not only shoot themselves in the foot but happily reload while you are scrambling to stop them.
I've worked on an enterprise application serving hundreds of millions of users and this exact error went out the door.
So no, practically speaking, this absolutely does not get caught right away. And if the specification is this sloppy, it should be thrown out and redone.
The specification is not sloppy, it specifies precisely the wire format, and does expressly cover this problem of how the values MUST be interpreted. The specification does not cover how the application should render the amount when showing it to the user, so when applications show the amount to the user they can of course still render it in a culturally appropriate way.
Woah, this is beyond just "bitter taste." If these values are potentially stored in JS Numbers, this scheme is completely dead on arrival. It is not acceptable for currency to be stored in a floating-point data type, full stop. This proposal needs to at a minimum define a datatype for how these values should be stored, not just leave it up to implementations to throw it at `var currency = x;`
This RFC is woefully underspecified, and the fact that there's an amount of its already-small specification devoted to "7.5. Bitcoin Address" makes me question their priorities and destroys a lot of confidence in the proposal.
I think you’re exaggerating the severity of the issues. “Such-and-such an integer must be less than 2⁵³” is normally a reasonable constraint to make life easier for people across all environments, and to make some such constraint is typically a good thing, rather than leaving it unspecified. I just think that the limit is on the low side here and probably unjustified due to what else is going on—and that perhaps this should be one of the rare cases where you deliberately don’t specify any limit (to the magnitude of unit or the length of fraction), and leave it to the client to decide what makes sense.
On the Bitcoin part: that’s just putting an entry in the registry, a perfectly reasonable and normal thing to do in such a specification. They’ve included entries for four of the main traditional banking systems, and two of the main new-generation systems that people are sure to want to combine this with.
If you deal with money, you do have to store the fraction separately anyway and clearly should not use floating point. But that's beyond the point. The upper bound is there to ensure that you do not have to use BigNum in languages like JavaScript, not to tempt you to simply represent the amount in a double.
> The upper bound is there to ensure that you do not have to use BigNum in languages like JavaScript,
I think that is a far too generous read of the document. I think it's because they wanted you to be able to use a JS Number to store the value, which is the Wrong Thing To Do. In fact, using two BigInts to separately represent the fractional and whole pieces of the currency would be far better.
This is the kind of ambiguity that I refer to when I say this is underspecified.
Eh, it’s not underspecified. It’s just… strangely specified, in a way that people will ignore and misparse. But then, if it had been specified in any other way people would have ignored and misparsed it too.
People going to put money in floats unless you make it impossible. Then they send it via json and round and probably over or under flow and all sorts of amusing bugs result.
If JavaScript numbers work up to 2^52 that could precisely represent $45 trillion in cents.
IMHO if they had a choice between dropping Javascript support in preference of languages with BigInt support, or dropping support for payments larger than $45 trillion, they probably made the right decision.
I know. That was meant as a joke somehow. But nevertheless, you can email the authors and tell them about your concerns. I think there's a process of improving RFCs via errata.
It's an informational RFC which is already published. So there's no review process anymore, it's done already. And as it's informational, it's not a "real" standard (no going through implementations etc)
If you don’t need to work with the value, store it in a string. If you do, use a proper decimal type. (Your question may then apply to the internals of the decimal type, but the point is that that should be transparent to the developer accessing the decimal value.)
Meh, from what I've seen so far, it's just so people see, e.g. 2.55 $/gal with the tiny nine in the corner, stop by and get charged 2.559 $/gal (essentially squeezing that last cent out of customers.)
I'd be interested to hear if anyone else has seen any digit other than nine in the tenth-of-a-cent column though.
I believe it's because gas prices are quoted with tax (which is unusual in the US), and there is a federal tax ending in 9 tenths of a cent. Probably lobbied by the small 9 marquee digit manufacturers of america.
Australian fuel prices are listed in cents to one decimal place. >80% of the time the last digit is a nine, the rest of the time it’s most commonly a 5. I’ve seen other odd digits rarely, with even numbers just about unheard of. But what you actually pay will be rounded to the cent, or to the nearest 5¢ if you pay in cash.
I think this is a neat idea, but it seems like the UX of it is a bit fraught for two reasons:
1. It doesn't seem like there's any callback mechanism. Once I transfer money, the source has no knowledge of that. If this is used for an invoice, the invoice needs to wait for the transfer to happen on the back-end for the source page to become aware that it happened. There seems to be no possibility of a "thanks for paying" URI that can be triggered after payment. This limits practicality for non-donation payments.
2. Each payto URI represents one payment method. Any payee who wants to accept money in one of a few different payment methods must provide separate URIs. This offloads the burden of knowing _how_ to pay to the user. If there's a list of five payment methods (as five payto URIs), I need to be aware of which ones I have apps for that my user agent can interact with. Some may trigger an error. Versus another world where I click a single link (payto URI) representing five payment methods in one and my user agent asks which app/account/etc I want to pay from.
This reminds me a lot of the UPI payment scheme. National Payments Corporation of India has defined the UPI as an interoperable format for payments between bank accounts. It has worked out beautifully in last few years and as someone who has worked extensively with applications around UPI, a common global standard around payments would go a long way to not only enable safer and more seamless payments infrastructure but also act as a countervailing force to the duopoly of VISA and MasterCard.
UPI is the one thing I consider very well executed by the Indian govt. I'm glad it exists, even though I don't use it much. It seems to be helping every Indian daily.
Looking at the RFC, the grammar is not well-defined:
'opt-value' is specified as any amount of 'pchar'[0], which includes both '&' and '=' (the delimiters between opts, and between opt-key and opt-values, respectively).
So in order to parse a payto-link, you either go eager and have only one option in the string, or lazy and my valid opts 'description=Food & drinks' will error out on a missing value for the ' drinks' authority-specific option, or go nuts and have parser-specific behaviour.
I don’t think that’s quite a fair representation of reality. “Standards Track” RFCs are fully-baked internet standards, and “RFC” is a misnomer the cause of which is “historical reasons”.
But as regards this particular RFC, the key details that are terribly easy to miss are right at the start:
• Independent Submission
• Category: Informational
In other words, the IETF is not “vouching for” this thing as they would be on standards track RFCs. (Another hint at this is that the registry the RFC establishes is established with GANA rather than IANA. And the URI format; I suspect that if it went through the full standardisation process it’d be pushed to payto:authority:path rather than payto://authority/path, the // style of URI being strongly linked with DNS resolution.)
(I completely forgot to check this when I first read the spec, and I’m used to reading these sorts of specs and checking their status. Read my earlier comments bearing this in mind.)
Does anyone understand how would this work if different payment methods had to be processed by different programs? As far as I understand, protocol handlers can only be registered for a protocol/scheme in general but not be limited to a protocol with a particular parameter as e.g. payto://IBAN/ or payto://bitcoin/.
If you’re dealing with a web app registering itself as a protocol handler, the scheme is the highest precision you get: navigator.registerProtocolHandler("payto", "https://bank.example/payto-handler/%s"). So there, you only get the protocol level of granularity. You might therefore set up bank.example and bitcoin.example, and now when you click on a payto: link, the browser will say “do you want to open this link with bank.example or bitcoin.example?”
On mobile platforms, I’m not certain, but you may be able to have the bank app only register for payto://iban/ (and any other payment authorities it supports) and the Bitcoin app only register for payto://bitcoin/.
There’s a big difference between the pull and push models.
The pull model is where I provide you with my details, and you draw money from me. Credit card numbers are the best-known mechanism for this. Ecommerce uses the pull model almost exclusively, because it lets the retailer confirm the payment and start the next step (fulfilment of goods) immediately.
The push model is where you provide me with your details, and I send money to you. This is seldom used for ecommerce because it requires reconciliation, for you to observe that you have received the money (which may take a greater period of time, depending on the systems involved—a lot of the world still operates on nightly clearing) and correlate payments with orders. This is used for much more casual things like people sending money to one another, or for larger amounts of commerce where transaction fees are much lower this way and maybe you don’t actually need the payment to be confirmed today.
For the pull model, your payment provider needs to know how to take money from the account details I provide. Sometimes this doesn’t work out, e.g. if someone has an American Express card but the merchant only accepts Visa and Mastercard.
For the push model, each sender needs to be able to target money to the account details the recipient provides. For example, I may be able to send to an Australian bank account by BSB and account number, but if you give me an American bank account, I won’t be able to pay to it directly but will have to figure out some kind of international transfer, potentially involving routing it through a third party.
The payto: URI scheme is the push model. For payto://stripe.com/… to make sense, each person’s bank would need to know how to send money to the nominated Stripe account. But that’s not how Stripe works; Stripe payments operate by the pull model.
> Ecommerce uses the pull model almost exclusively
This varies by country - the majority of e-commerce retail transactions here in Finland operate on a push model - in checkout you get redirected to your bank or wallet provider where you login (2FA) and authorize the transaction.
The merchant usually gets confirmation of payment immediately.
In fact I am not sure if there's any other country that likes the "pull" model as much the United States does. Wherever it exists it's there mostly due to historical reasons - in the past it was not possible to quickly validate and push a transfer, so you needed credit card companies to underwrite a small amount of credit (between now and end of month settlement). Kind of similar like how the US is so backwards when it comes to regular bank transfers (good luck using SWIFT). And how the Fed dollar is not exactly the same as the eurodollar. Some countries just like to be special :)
this RFC describes a type of resource, it does not care about how it will be processed. For example you could use the iban number for your "pay with stripe" buttons like this :
`<button data-payto="payto://iban/123456789">pay with stripe</button>
then you use stripes javacript library to handle it. if you do this you can trivially use multiple gateways at the same time in a flexible way.
I don't see Stripe's involvement in this at all: Stripe has no access to your bank account. Stripe might provide an IBAN for the publisher to provide a payto URI with. It seems like the whole point of this setup is for the user agent to decide which app to open to initiate a transfer to the destination.
For Stripe, this scheme is sort of irrelevant. If Stripe wants to offer the ability for someone to transfer money to an IBAN (or any other account identifier) through a webpage, they can just...do it. They don't need a URI, they just have a JS function which triggers a payment flow.
I would appreciate if the spec explicitly stated that requests using this scheme are neither value carrying nor authorizations. It would avoid so much hassle if they clearly stepped back from any appearance that this is a money transmission mechanism.
Prior author of finance-related internet standards drafts here. This is quite a simplistic and Eurocentric proposal.
The core design problem I see is that, in terms of the overall use case, it may in practice already often be the case that an existing identifier, not designed for payments, is used to identify the recipient (for example, an email address, phone number or nationally issued personal or corporate identifier) and that the actual settlement method (bank transfer, paypal, bitcoin, physical goods transfer, etc.) is not specified.
However, in this design you see that the settlement method must be specified along with the recipient, which is functionally nearly equivalent to providing (http://closed-system.com/method/specific/URI) thus largely devaluing the payto:// proposal.
A 'real world' use case for global payments: "I want to transfer some value over there": where there is defined, and some value is defined, but the potentially multiple means and steps to achieve the result may be many and varied and depend upon various additional criteria or preferences (cost, speed, trust, volume and asset type limitations, accounting or regulatory requirements, requirement for confirmation of delivery, error handling potential, day of week, time of day, holiday, reversibility, etc.).
Additional design problems are that there is no transaction or invoice identification system specified which will deeply frustrate customer service/auditing/reconciliation, temporal limits are not possible to specify, and that the approach of shoving all required metadata for a transaction in to generic fields without specifying their formatting is going to cause havoc with all sorts of use cases particularly the disparate allowable character ranges of thousands of banks' various AML/KYC field requirements for SWIFT transfers.
I also note that the proposal comes from Switzerland (home of SIX/SWIFT) and that its de-facto enforcement of ISO4217 effectively holds users of the protocol hostage to that central authority in terms of which currencies/asset types they are allowed to trade in.
It's pointless to add Paypal's closed pay-by-email here don't you think? You can only pay pal from another pay pal, so you can just use paypal:// scheme..?
Thinking about it it's also pointless to have multiple target types. Most traditional banks can only do IBAN or ACH. Although digital ones like Monese, Transferwise and Revolut can do any so maybe there's some merit for them.
How would that happen, exactly? If you were to have my bank account number you could give me money, but you couldn't just take it out. It's not like a credit card number.
Have you never had anything billed to your bank account? You give them your routing number and account number, and they take the money directly. Some sites will make you prove it's your bank account by asking you for the amount of two small deposits, but many don't.
This isn't hypothetical. It happens.
> In an attempt to prove that the public furore over the 2007 UK child benefit data scandal was unjustified, [Jeremy Clarkson] published his own bank account number and sort code, together with instructions on how to find out his address, in The Sun newspaper, expecting nobody to be able to remove money from his account. He later discovered that someone had set up a monthly direct debit for £500 to Diabetes UK.
Not from this. This is for sending money (the push model I speak of in another comment here); in-app purchases are apps demanding money (the pull model) and getting confirmation.
I don’t see the conceptual difference. Could one not describe the HTML (containing a payto: link, delivered to a web browser), as a “push”, and a subsequent click on that link as a “confirmation”?
Clicking on the link doesn’t do anything. It might open a banking app, where the user could make the suggested payment, or perhaps alter it, or perhaps not do it after all.
This sounds great. Instead of trusting each company to implement their own billing system with some payment processor, just have the payment processors and banks provide "apps" that support these protocols, and users can chose which one to use to complete their payment.
One interesting follow up question in who covers the processing fee (e.g. the ~3% or so that Braintree or Paypal currently take)? Today, processing fees are mostly hidden to the user. If the user can chose their own payment processor, will they be required to cover the processing fee instead of the merchant?
> Instead of trusting each company to implement their own billing system with some payment processor, just have the payment processors and banks provide "apps" that support these protocols
To me, this sounds dangerously close to the argument for the W3C standardization of DRM in the browser. I remain wary.
Possibly. But I remember the time of Shareware, especially on the Amiga platform. It seemed that every little itty-bitty utility program on the Amiga cost some small amount of money. Meanwhile, all the popular programs on PC (DOS and Windows) and Unix (Sun etc.) were mostly GNU-style free software, and guess who won that development? I’m worried that the entire currently-free web will stagnate by all web sites feeling forced to adopt this pay-by-the-click model.
However, you are certainly right in that the current ad-supported model is driving engagement, or, should I say, “enragement” clicks, which is certainly not doing much good.
Can this scheme/standard be denied to some parties? Are there vectors for censorship or deplatforming (through denial of payment) that can be guarded against?
Interesting, and potentially useful to decrease payments friction, although the challenge with these sorts of transfer schemes is that non-repudiation of contractual “promises” is not addressed.
Oh yeah, aren’t ACH numbers fraud risks too, if they’re public?
I remember a story about a major German bank who reused an IBAN for one of their treasury accounts and honoured direct debits for quite some time, so there are some risks with IBANs being known in some cases.
I think that removing friction will also make fraud much easier and prevalent.
IBAN numbers are not secret and are on payment cards and websites already. If that causes problems the system or vulnerability should be fixed, not try to twist in turns to keep those numbers secret.
UPI payments are built on a very similar standard [1]. The way click jacking is circumvented is two fold. Firstly, there is 2FA required for completing any UPI payment. Secondly, every payment request is mapped to a receiver who must have completed their KYC. In case of suspected fraud there is a redressal and recovery process.
Because otherwise each website ends up implementing the same functionality. I'm waiting for the moment where I don't have to type my account data into a random website, but can pay using my bank's application directly.
I guess fart app that pushes update to claim URI scheme cannot really do that anymore - only first come first served scheme is enabled. I guess if user uninstalled their banking app and clicked for payment and then fart app appears like your banking app and tries to steal your password...
> Interactive applications handling the 'payto' URI scheme MUST NOT initiate any financial transactions without prior review and confirmation from the user and MUST take measures to prevent clickjacking.
Isn't that true for all RFCs? Isn't that the point of an RFC, to say how things should work and interoperate?
You can criticize it for not being detailed enough or it not being realistic for someone to meet the requirements, but the point of an RFC is to say how it should work, not show it working that way.
Just because the RFC says to do it doesn't mean it's going to be done. How long did it take the browsers to solve clickjacking?
> Please don't comment on whether someone read an article. "Did you even read the article? It mentions that" can be shortened to "The article mentions that."
Fair, I apologize. I can't edit the comment anymore to remove it.
I assumed the parent didn't read that part since I assumed that if they did they would comment on that section, but I should not have worded it that way.
Conceptually, I love the idea of promoting push payments, because it has so much potential to reduce "credential mishandling" fraud. I also like the idea of putting the browser in control over presentation because that has the potential to increase trust (i. e. a payment flow that takes place outside the context accessible by malicious JavaScript, or tweakable to different paranoia levels based on user and bank preferences.
But I don't see this solving the acceptance cost problem. At the end of the day, too many people are living on credit, whether due to personal preference (point collectors) or financial need. That means any new API is just going to have to be poured on top of the existing, expensive, complex wedding cake of firms that is credit card acceptance.
It might be nice to see something like FedNow arrive as a low-overhead option, but if you have to discard every customer who can't pay now, you'll also provide a link to a card acceptance option too.
• It allows commas, which will just be stripped on execution. This feels like it’s just inviting errors unnecessarily, especially given that some parts of the world use comma (,) as their decimal separator and full stop (.) for grouping, rather than the other way round. I see no compelling reason for allowing grouping at all.
• “The 'unit' value MUST be smaller than 2^53. If present, the 'fraction' MUST consist of no more than 8 decimal digits.” Both of these feel a mite surprising, and the combination of them far more surprising. The 2⁵³ limit is doubtless to allow it to be safely stored in a 64-bit floating point number, specifically for JavaScript’s sake; but (dealing with this part first) do you know how small 2⁵³ is? 9 quadrillion. That’s honestly not that large. I’ve handled a 100 trillion dollar note, and that’s hardly the highest any currency has ever gone. (Admittedly, the sorts of currencies where this is happening probably have limited use for a payto: URI scheme at the time.) But anyway, skipping onto the second part, a fraction of up to eight digits. Skipping over the apparent arbitrariness of the number (which happens to match Bitcoin’s division), if you’ve made concession to treat the unit as a Number, what about the fraction? If you wanted to retain eight decimal places of significance, you’d be limiting your unit to 2⁵³ ÷ 10⁸, about 90 million, which is obviously too low, so you clearly can’t be meant to be representing the whole thing as a Number, so why that restriction on the unit? So yeah, both of these limits simply feel weird to me.
But other than these quibbles, I say: finally! I’m really glad about this and hope it gets adopted by banking apps and the likes quickly, and added to the HTML spec’s safelisted schemes (https://html.spec.whatwg.org/#safelisted-scheme) so that banks’ web apps can also navigator.registerProtocolHandler("payto", "https://bank.example/payto-handler/%s") soon. And also that Australian banks either register some way of addressing their accounts as a payto payment target type, or adopt IBAN.