w3c / webpayments

The document repo for the Web Payments Working Group
https://github.com/w3c/webpayments/wiki
Other
257 stars 62 forks source link

PROPOSAL: Pass the list of supported payment methods and the method-specific data in a single object #77

Closed adrianhopebailie closed 8 years ago

adrianhopebailie commented 8 years ago

From the discussion at #37

The payment request will contain (among other things)

  1. A set of supported payment methods
  2. Optional request data that is specific to one or more payment methods

An efficient way to pass this data in the payment request is to use an array of objects, each containing important request data and each indicating which payment method the data applies to.

An example would like this:

[
  {
    "methods" : ["bobspay.com", "visa+tokenized", "visa+legacy", "mastercard"],
    "data" : {
      //Data in here is relevant if any of the above methods is used.
    }
  },
  {
    "methods" : ["bobspay.com"],
    "data" : {
      //Put some data in here that is relevant for bobspay.com payments only
    }
  },
  {
    "methods" : ["bitcoin"],
    "data" : {
      //Put some data in here that is relevant for bitcoin payments only (like the BTC price)
    }
  }
]
msporny commented 8 years ago

I think I'm in favor of this proposal, @adrianhopebailie, but want to clarify a few things before being a +1 on it. I'll also try to make assertions rather than ask questions in an attempt to get to an understanding more quickly. You are asserting that a payment request will:

  1. Be composed of a set (array) of one or more acceptable payment methods.
  2. Associate payment method-specific data with each item in the array.
  3. Allow an array for the payment methods associated with each item in the array (I feel a bit uneasy about this one, haven't thought it through but it feels like it could add UI complications - like if you specify a payment method twice in the set of acceptable payment methods and the prices are different, you'll have to expose that difference to the customer).

I am asserting that, in addition to the two items above, a payment request will:

  1. Use whatever glossary term we decide on, in the singular form, for what you note as "methods" above (I thought we had decided on scheme?). So, "method" instead of "methods". As a general rule, we will use the singular, even for properties with associated arrays.
  2. Not shove everything in a "data" property, but allow the key-value pairs to live at the same level as "method" above.

To provide a more accurate picture of what I'm talking about, here's an example below:

var paymentRequest = {
  acceptablePaymentMethod: [{
    paymentMethod: ["VisaLegacy", "DiscoverLegacy", "MastercardLegacy"],
    requestedPayment: {
      amount: '54.18',
      currency: 'USD'
    },
    propertyFoo: 1,
    propertyBar: "XYZ",
    ...
  }, { ... }
  ]
};
dlongley commented 8 years ago

As payment methods may each have their own special data, I recommend we simply enumerate them each individually, even if that means repeating prices (note that they may often not be the same price anyway). I don't think that will be difficult for payees to generate and it will be less ambiguous. So I was thinking something more like this:

var paymentRequest = {
  acceptablePayment: [{
    paymentMethod: "VisaLegacy",
    transfer: {
      amount: '54.18',
      currency: 'USD'
    },
    specialVisaLegacyThing: 1,
    ...
  }, {
    paymentMethod: "MastercardLegacy",
    transfer: {
      amount: '54.18',
      currency: 'USD'
    },
    specialMastercardLegacyThing: 7
    ...
  }, {
    paymentMethod: "DiscoverLegacy",
    transfer: {
      amount: '60.00',
      currency: 'USD'
    },
    specialDiscoverLegacyThing: "foo",
    ...
  }, ...],
  ...
};
adrianhopebailie commented 8 years ago

@dlongley I'm not against this but worry that we will end up with a LOT of redundant data. I think we underestimate the number of payment methods that will evolve. Bare in mind that there may be 10 ways to do a "card payment" - clear PAN, tokenised, encrypted etc. - and each is a different payment method.

Perhaps a better way to do this is to have a root that defines the payment request data and then the methods can override this;

var paymentRequest = {
  transfer: {
    amount: '60.00',
    currency: 'USD'
  },
  acceptablePayment: [{
    paymentMethod: "VisaLegacy",
    transfer: {
      amount: '54.18',  //Discount for using VISA
      currency: 'USD'
    },
    specialVisaLegacyThing: 1,
    ...
  }, {
    paymentMethod: "MastercardLegacy",
    specialMastercardLegacyThing: 7
    ...
  }, {
    paymentMethod: "DiscoverLegacy",
    specialDiscoverLegacyThing: "foo",
    ...
  }, ...],
  ...
};
webpayments commented 8 years ago

I am of the "optimize when needed" school. I agree with Adrian that there are potentially many many payment methods accepted for any transaction. Especially if you consider the combinatoric explosion that comes from the cross product of payment methods with credential sharing / loyalty programs:

{ method: [ visa+legacy, visa+token, bitcoin, paypal ], modifier: [ address, address+personal-info, address+create-loyalty-account] }

where modifiers cause price reductions / modifications (if you share your address AND your birthday / home town / favorite sports team with us you get 10% off!).

Having said that, I am not worried about the size of the data. It compresses aggressively and is easily machine-composed. If it turns out to be a problem in the wild, we can always optimize it later by adding some sort of a default mechanism (where default values for fields fill in missing fields in payment method details) or something.

On Wed, Feb 3, 2016 at 6:10 AM, Adrian Hope-Bailie <notifications@github.com

wrote:

@dlongley https://github.com/dlongley I'm not against this but worry that we will end up with a LOT of redundant data. I think we underestimate the number of payment methods that will evolve. Bare in mind that there may be 10 ways to do a "card payment" - clear PAN, tokenised, encrypted etc. - and each is a different payment method.

Perhaps a better way to do this is to have a root that defines the payment request data and then the methods can override this;

var paymentRequest = { transfer: { amount: '60.00', currency: 'USD' }, acceptablePayment: [{ paymentMethod: "VisaLegacy", transfer: { amount: '54.18', //Discount for using VISA currency: 'USD' }, specialVisaLegacyThing: 1, ... }, { paymentMethod: "MastercardLegacy", specialMastercardLegacyThing: 7 ... }, { paymentMethod: "DiscoverLegacy", specialDiscoverLegacyThing: "foo", ... }, ...], ... };

— Reply to this email directly or view it on GitHub https://github.com/w3c/webpayments/issues/77#issuecomment-179190518.

-Shane

dlongley commented 8 years ago

I have a lot of agreement with Shane (keep it simple and only optimize when needed), but I also like @adrianhopebailie's latest suggestion of defining a root (common) set of parameters at the top-level and then including payment method specific data and overrides in the acceptablePaymentMethod section. I think that approach might be simple enough to understand and it addresses redundancy concerns. I'd like to hear more opinions from others on these two approaches.

dlongley commented 8 years ago

Let's keep in mind that that 10 ways to do something likely doesn't really need optimization.

rsolomakhin commented 8 years ago

Correct me if I am wrong, I am seeing three options available here. Based on my dreamt up examples below, all of these options are fairly close to each other. Perhaps Option 1 is still the cleanest, which will be easier to describe in the spec and tutorials. So I would prefer the simpler Option 1, although I am largely flexible on this question.

Option 1.

var paymentMethods = ["method1", "method2", "method3"];
var paymentMethodDetails = {
  "method1": {"field1": "value1", "field2": "value2"},
  "method2": {"field3": "value3", "field2": "value2"}
};

Option 2.

var paymentMethods = [{
  "methods": ["method1", "method2"],
  "data": {"field2": "value2"}
}, {
  "methods": ["method1"],
  "data": {"field1": "value1"}
}, {
  "methods": ["method2"],
  "data": {"field3": "value3"}
}];

Option 3.

var paymentMethods = [{
    "method": "method1",
    "data": {"field1": "value1", "field2": "value2"},
  },  {
    "method": "method2",
    "data": {"field3": "value3", "field2": "value2"},
  },  {
    "method": "method3"
}];
alexdown commented 8 years ago

I am also towards keeping each method's properties completely separate. Data common to more than one method may be duplicated, but I believe it'll be simpler to build the request this way (from the website's point of view).

If we go for the initial proposal ("merging" data common to more than one method into a single object) we assume that the website have this capability, which it may not (if modules handling payment methods are separate, maybe provided by different companies..).

Also, how to decide 'what' to merge: properties having the same key goes into the common object? Can we safely assume that there won't be properties with the same name but different meaning in two different payment methods?

adrianba commented 8 years ago

I do not agree with this proposal. In general we want to optimise for the develop experience. The current PaymentRequest API proposal accepts several different arguments and for a specific reason.

The four arguments are:

So the design of the API is to be clear on which things are different per transaction, which are likely to be constant, and separates out things that might not be needed to keep the developer experience simpler. We also get to benefit from the built in IDL-based argument validation that most browser engines provide in an easy way (I have received feedback about the specific WebIDL that needs to improve to support this). In general, browser APIs don't try to take a huge blob of data as a single data structure - we guide developers through the experience with more structured arguments and that is our goal here. I'm not suggesting that we're done with the arguments but I don't agree with a blanket "merge everything into a large JSON-like object" is a good proposal.

alexdown commented 8 years ago

Agree with you in principle, @adrianba, that allowing total freedom in putting everything inside a json structure duplicated for each payment method may be going too far. But the issue that different payments methods may change the total amount/line items exist, so it has to be addressed.

On a side note, it seems the general approach being discussed is of one, one-way communication between payee site and payment app, mixing payment method selection with payment execution.

I'm new here, so I'm not sure if this is a design choice resulting from previous discussion (if so, has it been captured somewhere, so I can get up to speed?), or just a working draft still subject to changes...

mattsaxon commented 8 years ago

Also consider in the size of the data that there may be multiple currencies offered for payment, so we may need to be able to apply some sort of filter, e.g. where the client says I want to pay in this currency or I only want to see payment types that fall into this category (I appreciate that this does run some risk of information disclosure by the client). (linked to #79)

adrianba commented 8 years ago

But the issue that different payments methods may change the total amount/line items exist, so it has to be addressed.

The title of this issue is "Pass the list of supported payment methods and the method-specific data in a single object". There are surely many ways to solve the issue of payment method impacting the total. I don't see why wrapping everything up (constant, variable, or rarely changing) into one huge JSON blob makes that issue go away?

Also consider in the size of the data that there may be multiple currencies offered for payment

Is this really needed in v1? This has almost never happened to me and when it did it was part of a much more complex interaction than most sites need. Our goal from the start was to propose something that solved core uses cases and then iterate fast.

adrianhopebailie commented 8 years ago

This was not discussed at the 4 Feb meeting. Pushed to 11 Feb meeting.

adrianhopebailie commented 8 years ago

This was not discussed at the 11 Feb meeting. Pushed to 18 Feb meeting.

adrianhopebailie commented 8 years ago

Addressed in https://github.com/w3c/browser-payment-api/pull/133 Will be discussed further in the Browser API repo