Search code examples
javapaypalpayment-gatewaypaypal-sandbox

Payflow Pro: blocking duplicate invoice IDs does not work


My web-application suffers from duplicate payment transactions. It uses Payflow Pro JAVA SDK to make a call to PayPal Gateway to process users payments via PayPal.

As, a short term solution, we decided to pass INV NUM, as suggested in this article, so PayPal can track it and reject the transaction with the same invoice ID with corresponding error code and message.

While testing the fix I am still getting statusCode 0 and transaction message APPROVED for the duplicate transaction. However for the duplicate transaction, the DUPLICATE flag is set true which I believe identifies it as duplicate one, but I don't understand if it means that the transaction was not processed successfully, meaning user was not charged second time.
The invoice generation method looks like this:

Invoice inv = new Invoice();

/* Set Amount. */
Currency amt = new Currency(pip.getFeeAmount(), "USD");
inv.setAmt(amt);
inv.setPoNum(poNum);
// INV NUM e.g.: 988755aa8aeb262a506ec01
inv.setInvNum(pip.getInvNum());
BrowserInfo bi = new BrowserInfo();
bi.setButtonSource(buttonSource);
inv.setBrowserInfo(bi);
return inv;

Does anyone can tell me why it doesn't work?


Solution

  • After, having chat with PayPal tech support and digging deeper into PayPal documentation, I got an answer to my question. The unique INV NUM approach doesn't work in my case of integration with PayPal. Instead to fix a problem, I need to generate and set unique Req Id for the transaction. More details about X-VPS-REQUEST-ID header is here. The PayPal stores the received request ID in the request table, so when you send a new transaction it will check if such request ID was used before, if yes then it will treat the transaction as a duplicate and return you response of the original transaction:

    Important: If you send in a NEW transaction with a previously used X-VPS-REQUEST-ID, the server ignores the new data and returns the response to the original transaction associated with that X-VPS-REQUEST-ID.

    The duplicate transaction will have flag DUPLICATE set to 1. Such behavior, requires me to handle additional case, when the original transaction failed because of invalid card expiration date for example, and second transaction was sent with valid expiration date. In such case, I have to generate new req ID, as otherwise I will still be getting failed response from the original transaction.

    NOTE: putting responsibility on the payment vendor is only an additional measure against duplicates and should not be considered as the primary solution for a problem. That is why I have to redesing my payment workflow to determine duplicate transaction before making a call to the payment vendor and handle it in a proper way.