I have gotten the PayPal API to work with one item and I'm now trying to get it to work with a whole "shopping-cart". I have encountered an error that I don't know how to solve. I suspect it might have to do something with the payment-jsons total value that represents the total cost of the whole transaction. However I don't know what to do about it.
Here is the error:
Error: Response Status : 400
at IncomingMessage.<anonymous> (E:\Users\willi\Documents\Node\Store\node_modules\paypal-rest-sdk\lib\client.js:130:23)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
response: {
name: 'MALFORMED_REQUEST',
message: 'Incoming JSON request does not map to API request',
information_link: 'https://developer.paypal.com/webapps/developer/docs/api/#MALFORMED_REQUEST',
debug_id: '9e8898a463ee3',
httpStatusCode: 400
},
httpStatusCode: 400
}
And here is the code in question
const pay = (req, res) => {
async function f() {
items = [];
req_items = req.body.body
let itemsProcessed = 0
req_items.forEach(item => {
console.log(item.id)
const param = item.id
Item.find({ _id: param })
.then((result) => {
const item_body = {
"name": result[0].title,
"sku": "001",
"price": parseFloat(result[0].price),
"currency": "EUR",
"quantity": item.amount
}
items.push(item_body)
itemsProcessed = itemsProcessed + 1
})
.catch((err) => {
console.log(err)
})
})
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait until the promise resolves (*)
console.log(items)
const create_payment_json = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": "http://localhost:3000/success",
"cancel_url": "http://localhost:3000/cancel"
},
"transactions": [{
"item_list": {
"items": [items]
},
"amount": {
"currency": "EUR",
"total": parseFloat(req.body.subtotal) // 25
},
"description": "Purcahsed from the Store"
}]
};
// console.log(req.body)
// console.log(create_payment_json.transactions[0])
paypal.payment.create(create_payment_json, function (error, payment) {
if (error) {
throw error;
} else {
for(let i = 0;i < payment.links.length;i++){
if(payment.links[i].rel === 'approval_url'){
res.redirect(payment.links[i].href);
}
}
}
});
}
f();
}
You are integrating the deprecated v1/payments PayPal API. You shouldn't be doing so for a new integration; the current API is v2/checkout/orders
, documented here.
Typically you'll want to create two routes on your own server, 'Create Order' and 'Capture Order', which return their own JSON when called. Then you can pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
But as for your problem, debugging an issue like this is much simpler if you simply log your request JSON to see what the problem with it is.
If you do so, you will see that the "items" array you are sending has an array inside of an array of only one item (the other array). That array shouldn't be there.
This seems the culprit:
"items": [items]
Here you decided to make an array, which was useful when "items" was a single item (no array). But when items is already an array, you shouldn't be putting the array into a new array -- the resulting JSON won't map to an API request, and PayPal will return an error.
What you should do is get rid of those brackets and ensure that at this point in the code execution, "items" is already an array (if it wasn't before).