I was trying to debug a problem related to refunding Paypal orders (in a sandbox environment) using order IDs (which were stored previously). Every time I tried to perform a refund, the Paypal API would return an INVALID_RESOURCE_ID
error, meaning that no such order existed. After much debugging, I have made a revelation with the initial process when I stored said order ID. The following method is how I am retrieving and storing said order id:
const onApprove = (data, actions) => {
// Redux method of saving checkout in backend with order ID via using data.orderID
dispatch(saveCheckout(data.orderID);
return actions.order.capture();
}
<PayPalButton
amount={totalPrice}
currency= "AUD"
createOrder={(data, actions) => createOrder(data, actions)}
onApprove={(data, actions) => onApprove(data, actions)}
options={{
clientId: "<placeholder>",
currency: "AUD"
}}
/>
I am using the recommended data.orderID
from the docs and yet, upon inspecting the network tab, the following is shown:
{"id":"5RJ421191B663801G","intent":"CAPTURE","status":"COMPLETED","purchase_units":[{"reference_id":"default","amount":{"currency_code":"AUD","value":"24.00"},"payee":{"email_address":"sb-sg4zd7438633@business.example.com","merchant_id":"EJ7NSJGC6SRXQ"},"shipping":{"name":{"full_name":"John Doe"},"address":{"address_line_1":"1 Cheeseman Ave Brighton East","admin_area_2":"Melbourne","admin_area_1":"Victoria","postal_code":"3001","country_code":"AU"}},"payments":{"captures":[{"id":"7A2856455D561633D","status":"COMPLETED","amount":{"currency_code":"AUD","value":"24.00"},"final_capture":true,"seller_protection":{"status":"ELIGIBLE","dispute_categories":["ITEM_NOT_RECEIVED","UNAUTHORIZED_TRANSACTION"]},"create_time":"2021-10-11T00:40:58Z","update_time":"2021-10-11T00:40:58Z"}]}}],"payer":{"name":{"given_name":"John","surname":"Doe"},"email_address":"sb-432azn7439880@personal.example.com","payer_id":"KMEQSKCLCLUZ4","address":{"country_code":"AU"}},"create_time":"2021-10-11T00:40:48Z","update_time":"2021-10-11T00:40:58Z","links":[{"href":"https://api.sandbox.paypal.com/v2/checkout/orders/5RJ421191B663801G","rel":"self","method":"GET"}]}
The id saved by onApprove
is 5RJ421191B663801G
but there is another ID under captures
and id
which is 7A2856455D561633D
. This is the actual order id I need to save in order to make the refund later on. However, I am struggling as to how I can retrieve this value as that id value seems to be only visible via the network. The objects returned via the onApprove and action.order.get()
methods only return the first "false" id. Any advice would be greatly appreciated.
These are two separate types of IDs, the order ID (used only during buyer checkout approval), and the payment/transaction ID (which only exists after an order is captured, and is the one needed for any later refund or accounting purposes)
Since you are capturing on the client side with actions.order.capture()
, this is where you would need to add a .then(function(data){ ... })
to do something with the capture data (particularly data.purchase_units[0].payments.captures[0].id
). That is the id you would use for a refund.
In actual best practice, if anything important needs to be done with the capture id -- such as storing it in a database for reference -- you should not be creating and capturing orders on the client side, and instead calling a server-side integration where that database write will be performed.
Follow the Set up standard payments guide and make 2 routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. Both routes should return only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should store its resulting payment details in your database (particularly the aforementioned purchase_units[0].payments.captures[0].id
, which is the PayPal transaction ID) and perform any necessary business logic (such as sending confirmation emails or reserving product) immediately before forwarding your return JSON to the frontend caller.
Pair those 2 routes with the frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
Or for react, use the official react-paypal-js