Hi Nathan,
Thanks for the additional details, and log.
Could you show me the shortcode you’re using to sell these? (the $110, and $115 ones)
I looked up the buyers you sent me, and for some (not all) I did find the duplicate, about a minute after the original. It looks almost as if they had clicked on the checkout button more than once, but I don’t know how likely that is.
I’m suspecting it may be something to do with a communication problem between your server and Paypal’s. If your server doesn’t get a clear ack from PayPal, it may retry, and it could end up as a duplicate if PayPal had actually gotten the first one.
Some APIs have something to prevent these duplicates (idempotency), but I’m not sure the PayPal Express Checkout one does. I’m studying the API docs for it.
Would you try something for me? Make a copy of this file: s2member-pro/src/includes/classes/gateways/paypal/paypal-checkout-in.inc.php
Find this line:
$paypal_set_xco["EMAIL"] = ($user) ? $user->user_email : $post_vars["email"];
Right below it add these:
$request_id = md5(serialize($paypal_set_xco));
$paypal_set_xco["PAYMENTREQUEST_n_PAYMENTREQUESTID"] = $request_id;
Keep the original of the file as a backup, and try the modified one. Do a test purchase to make sure the checkout is still working correctly. Then look in the s2 paypal-api log for that test, and see if the PAYMENTREQUESTID is there.
If the checkout test went well, leave it for a while and see if you get a duplicate charge again.