Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
adrianhopebailie opened this issue Feb 1, 2016 · 15 comments
Assignees
Labels

Comments

@adrianhopebailie
Copy link
Collaborator

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
Copy link
Member

msporny commented Feb 3, 2016

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
Copy link
Contributor

dlongley commented Feb 3, 2016

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
Copy link
Collaborator Author

@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
Copy link

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 <[email protected]

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
#77 (comment).

-Shane

@dlongley
Copy link
Contributor

dlongley commented Feb 3, 2016

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
Copy link
Contributor

dlongley commented Feb 3, 2016

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

@rsolomakhin
Copy link
Collaborator

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
Copy link
Contributor

alexdown commented Feb 4, 2016

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
Copy link

adrianba commented Feb 4, 2016

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:

  • A list of payment methods accepted by the merchant. You should think of this as a simple list of all the stickers a merchant would put in their window about payment methods accepted. This is likely to be fixed data that changes very infrequently for a merchant.
  • Payment details for this specific request i.e. what the web site visitor is being asked to make a payment for. This value will vary for each transaction and includes the transaction amount and optionally line items.
  • An optional payment request options object. These options alter the processing that the user agent performs for the transaction (for example whether or not shipping address should be collected). This is unlikely to vary from one transaction to the next. It may not be needed for some sites.
  • Optional payment method specific data. In my view, we don't yet have a lot of experience for how this might be used by different payment methods. Currently the spec says that the data must match up to the payment methods accepted by the merchant but it is possible that groups of methods might want to share data. It's also entirely possible that (especially for raw PANs, for example) that this data is not needed at all for some sites. It's probably that this data won't very for each transaction.

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
Copy link
Contributor

alexdown commented Feb 4, 2016

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
Copy link
Contributor

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
Copy link

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
Copy link
Collaborator Author

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

@adrianhopebailie
Copy link
Collaborator Author

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

@adrianhopebailie
Copy link
Collaborator Author

Addressed in w3c/payment-request#133
Will be discussed further in the Browser API repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants