I tried to integrate PayPal Express Checkout to my webapp (server-side REST) and I managed to: get create-payment working
However, when I tried to login with a sandbox test buyer account, it failed to process the payment.
There's a 400 Bad request error for the POST request:
POST https://www.sandbox.paypal.com/webapps/hermes/api/batch/setbuyer 400 (Bad Request)
with the following response:
{
"ack": "success",
"data": {
"buyerEligibility": {
"ack": "success",
"data": {
"eligible": true,
"clearedRT": false
},
"meta": {
"calc": "8f7cc8e266c07",
"rlog": "PVs6nBwuIQ9X2gSdIEqzR%2BxkmohYC3WlOiW4HauQ%2FY%2Fh%2BkWFfmr2pOeyxVs3sSiqXDydWuJ%2B6QWLAsZZVtRfIA_15d276b99bf"
},
"server": "xG7Ol-1A5r4xEqHEubzBtkj6LgLo88Z7UFOPmqsoK957Q11gkENbvzjGa02RjhyhvYG_ff2SZRFgHYp0Nq5rCCIdwQAwbwL-RkZ0piofvsP6-i9NmpkouuuH47EBynDbMencyfNKhT-cIewGtGK2jKUX_q0FaWq9Gx0MaRB6QBwINBmRQB5tAuklfWE8ooIwOO7szgPXVg9pOXWI2ukxup08j93HODToZ4DnSLuqCK6XM2M49-_DDSyS6GviI3gWrBy7BLOsHky"
},
"eConsent": {
"ack": "success",
"data": {
"required": false
},
"meta": {
"calc": "8f7cc8e266c07",
"rlog": "PVs6nBwuIQ9X2gSdIEqzR%2BxkmohYC3WlOiW4HauQ%2FY%2Fh%2BkWFfmr2pOeyxVs3sSiqXDydWuJ%2B6QWLAsZZVtRfIA_15d276b99bf"
},
"server": "-bDk6FVAJFycsTL-R5q_CGdrJwDz9XbAF9KqMHpr6QIMACZ6IA5zQ_BVyqi3jy6w9pKC5SS4TBrpDB_OJC0rU1W5wz5XBgo3ze_iOG0gDEwxuzu7WtAT1Nv5_VmLhmUWIdMm7qtgfy1y11v18zXSxhATUDaRI8hNdlnArSlBtKVNGWkhCD4OTp4KvSBXQ3lLHm-wCSrJzhpEmBoNZmDQMrd4wv1YEYA0VFPG1cPHapq9t4xJMLfiZOad10irqxJP"
},
"createCheckoutSession": {
"ack": "contingency",
"contingency": "PAYER_CANNOT_PAY",
"errorData": {
"cause": "",
"step_up_context": {}
},
"meta": {
"calc": "8f7cc8e266c07",
"rlog": "PVs6nBwuIQ9X2gSdIEqzR%2BxkmohYC3WlOiW4HauQ%2FY%2Fh%2BkWFfmr2pOeyxVs3sSiqXDydWuJ%2B6QWLAsZZVtRfIA_15d276b99bf"
},
"server": "-eKOVjOLP5i0k_9Et8_N5HyfLSVBzycsA2AE8UY8RD88MnM3729QBQoHY2eD3sMhSThBqdYmvFoARIAbkHNoOT9jsHzAUCk1CtbA717xHK5gSuYujf5mvuDJQFXWlPEDBk7XFlZSyhUWy8VGKvYWwWhuTSzcjMdKIzRI_XTjfA2hQpzIvkbRQ5jLMDIIKeNm1XrF3mEMN3gkHzZIc2OBiRaVEA2Q0se_uVgEEGIbSgN2aeSOeh4WiMC08zUCvmdCLyCP0ZyE24fzDvL4ZMUurG"
}
},
"meta": {
"calc": "8f7cc8e266c07",
"rlog": "PVs6nBwuIQ9X2gSdIEqzR%2BxkmohYC3WlOiW4HauQ%2FY%2Fh%2BkWFfmr2pOeyxVs3sSiqXDydWuJ%2B6QWLAsZZVtRfIA_15d276b99bf"
},
"server": "JwJRYq2SF3kUujC16-VsiMQu8IDN_RxPNOz8wY8m8YD4P3PzhHZB73hNd_IM9PktfJcPPHx2RyVUk1PV8bC2lLtejwTFKzq-7QDM9nLmxJLw7os2tgLnGYAebFJAkmIt2fFvlncVMrAg9bAsMF9INhPqixaCEWn7ug9OcPCci_3autJi3cvmTLb_8XvTaGBpPxI0ASQnkXTSVJa2GPIptYhGVHFN5N92hFdxzwp2uYQhHeJrePmExV4NlLd0s_wa"
}
My client side implementation for PayPal Express Checkout:
class PayPalButton extends Component {
render() {
const Btn = paypal.Button.driver('react', {React, ReactDOM});
const CREATE_PAYMENT_URL = `${ROOT_URL}/paypal/create-payment/${this.props.regId}`;
const EXECUTE_PAYMENT_URL = `${ROOT_URL}/paypal/execute-payment/${this.props.regId}`;
const token = localStorage.getItem('deotoken');
let client = {
sandbox: 'TO_BE_REPLACED_WITH_SANDBOX_CLIENT_ID'
};
let payment = () => {
return paypal.request({
method: 'post',
url: CREATE_PAYMENT_URL,
headers: {
authorization: token
}
})
.then(function(data) {
return data.id;
});
};
let onAuthorize = (data) => {
return paypal.request({
method: 'post',
url: EXECUTE_PAYMENT_URL,
headers: {
authorization: token
},
json: {
paymentID: data.paymentID,
payerID: data.payerID
}
}).then(function() {
// The payment is complete!
// You can now show a confirmation message to the customer
console.log('done');
});
};
return (
<div>
<Btn env={'sandbox'}
client={client}
payment={payment}
commit={true}
onAuthorize={onAuthorize}
/>
</div>
);
}
My server side implementation):
module.exports = {
createPayment(req, res, next) {
const { registration_id } = req.params;
const { user } = req;
Registration.findById(registration_id)
.populate({ path: 'category', model: 'category' })
.populate({ path: 'orders.meal', model: 'meal' })
.then(reg => {
if (reg) {
const categoryItem = [{
name: reg.category.name,
sku: reg.category.name,
price: reg.category.price,
currency: 'MYR',
quantity: 1
}];
const ordersItems = reg.orders.map(order => {
return {
name: order.meal.name,
sku: order.meal.name,
price: order.meal.price,
currency: 'MYR',
quantity: order.quantity
}
});
const create_payment_json = {
intent: 'sale',
payer: {
payment_method: 'paypal'
},
redirect_urls: {
return_url: 'http://localhost:8080/',
cancel_url: 'http://localhost:8080/'
},
transactions: [{
item_list: {
items: [...categoryItem, ...ordersItems]
},
amount: {
currency: 'MYR',
total: reg.totalBill
}
}]
};
paypal.payment.create(create_payment_json, function(err, payment) {
if (err) {
next(err);
} else {
res.send(payment);
}
})
} else {
return res.status(422).send({error: 'Registration not found'});
}
})
.catch(next);
},
executePayment(req, res, next) {
const { registration_id } = req.params;
const { paymentID, payerID } = req.body;
const execute_payment_json = {
payer_id: payerID
}
paypal.payment.execute(paymentID, execute_payment_json, function(err, paypalResponse) {
if (err) {
next(err);
} else {
if (paypalResponse.state === 'approved') {
const payment = new Payment({
user: req.user._id,
registration: registration_id,
amount: paypalResponse.transactions[0].amount.total,
currency: paypalResponse.transactions[0].amount.currency,
paypalPaymentId: paypalResponse.id
});
payment.save()
.then(p => res.send(p))
.catch(next);
} else {
res.status(422).send({ error: 'Payment not approved' });
}
}
});
}
};
What is the issue? How can I make this work?