academe / SagePay-Integration

HTTP Messages for the Sage Pay REST (Pi) gateway.
GNU General Public License v3.0
9 stars 5 forks source link

Support saved cards #47

Closed judgej closed 7 years ago

judgej commented 7 years ago

The way the gateway works, or is documented, can be a little unclear (to me!). It shows a payment being made with a "card" object. That card object has been generated using a merchant session key to create a temporary tokenised card.

Now, a saved card can also be used, but a saved card is not generated using a merchantSessionKey. It happens to have the save ID as the one that was (checked and confirmed) but is not linked to the session key. But the documentation does not give this as an example, so it is not clear how it works, since it states that the merchantSessionKey is mandatory, when clear;y it is not (probably) unless you choose to relink a security code with it.

I think the issue is that "cardIdentifier" is overused. It represents both temporary card details with a 400 second lifetime, and saved card details that have been verified and stored in the gateway for future use. I suspect these are two very different resources.

judgej commented 7 years ago

It may be that we have two card types that can be passed into a payment request: a temporary card token (with mechantSessionKey) and a reusable card token (which can be saved for further use if needed).

The Response\CardIdentifier is the temporary card token, and payments support that only in this library right now. The Response\Model\Card is the (optionally) reusable card token.

judgej commented 7 years ago

Fairly new documation page shows what the reusable card looks like:

http://integrations.sagepay.co.uk/content/tokens

It shows how the dropin scripts can be used to link the CVV to the reusable card token, without the need for that CVV to be sent to the merchant site.

With a CVV attached, payment is done like this:

"paymentMethod": {
       "card": {
           "merchantSessionKey": "<merchant-session-key>",
           "cardIdentifier": "<card-identifier>",
           "reusable": true
       }
   },

without a CVV attached, it looks like this:

"paymentMethod": {
       "card": {
           "cardIdentifier": "<card-identifier>",
           "reusable": true
       }
   },

Not forgetting that both of these will need save: true included if the card is to continue to be reusable (TBC though, as the docs are a little ambiguous).

judgej commented 7 years ago

I think I have it now.

The Request Card model is a temporary card token using the session key and the card identifier, with an optional "save" parameter. It will be used as a payment method.

The Response Card model is the card details returned to the merchant site. This may be a reusable card token or a non-reusable card. If reusable then it can be used as a payment method in another transaction without any further changes, since it now implements the payment method interface.

judgej commented 7 years ago

It seems to the case that once a card has been used with the save flag set on its first use, it will remain reusable for all subsequent uses without the need to keep setting save. In fact, setting save to false on a subsequent use leaves the card reusable. That doesn't seem right, and I'll check up on that with Sage Pay.

judgej commented 7 years ago

These are essentially the options for sending a card as a payment method:

  1. card-identifier+session-key = tokenised on front end.
  2. card-identifier+session-key+reusable = saved card with a new CVV attached.
  3. card-identifier+reusable = saved card with no CVV attached.

These are three different card objects, which we will call:

  1. SessionCard (lasts 400 seconds, then discarded)
  2. ReusableCvvCard (must be used within 400 seconds, then link must be refreshed)
  3. ReusableCard (lasts until it is explicitly removed)

All three can take the "saved" parameter. 2 and 3 seem to ignore the value of that parameter at this time.

judgej commented 7 years ago

These are the four valid combinations of fields that make up a card payment type. Both reusable/save flags default to FALSE, so setting the field to "false" or leaving it blank are equivalent:

card-identifier session-key reusable save notes
first-use string string FALSE TRUE Card tokenised on the front end; saved as reusable after transaction.
first-use string string FALSE FALSE Card tokenised on the front end; not reusable after transaction.
second-use string n/a TRUE FALSE Reusing a saved card; no CVV checks.
second-use string string TRUE FALSE Reusing a saved card; with CVV checks.

All other combinations (e.g. TRUE+TRUE, or FALSE+any+missing session-key) are invalid. So it looks like the save flag is not supported for a reusable card and so withSave() can be removed from those. (TBC - awaiting confirmation from SP - yes, confirmed the above is correct)