I have integerated PayPal Client Side REST to my website. I have used the sample code provided from link below:
https://developer.paypal.com/demo/checkout/#/pattern/client
This code below worked over a month, however today it shows below error
Error: Request to post https://www.sandbox.paypal.com/v1/payments/payment
failed with 400 error
{
"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": "a26904ff6211a"
}
my code follows:
<div id="paypal-button-container" class="info"></div><script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
// Render the PayPal button
paypal.Button.render({
// Set your environment
env: 'production', // sandbox | production
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
client: {
sandbox: '<?=SANDBOXPAYPAL?>',
production: '<?=PAYPAL_TOKEN?>'
},
// Set to 'Pay Now'
commit: true,
// Wait for the PayPal button to be clicked
payment: function() {
$('#card').attr('checked',true);
// Make a client-side call to the REST api to create the payment
return paypal.rest.payment.create(this.props.env, this.props.client, {
transactions: [
{
amount: { total: '12.99', currency: 'GBP' }
}
]
});
},
// Wait for the payment to be authorized by the customer
onAuthorize: function(data, actions) {
jQuery.ajax({
type: "POST",
url: "ipn.php",
data: data,
success: function(data){
}
});
return actions.payment.execute().then(function() {
document.querySelector('#paypal-button-container').innerText = 'Payment Complete!';
});
}
}, '#paypal-button-container');
</script>
Your code does not quite match the example, but I am also using the client-sdie API from a Laravel Shoping Cart I am building, I use AJAX to push the payment data back to my system this way:
onAuthorize:function(data, actions)
{
console.log("onAuthorize()");
console.log("Dumping DATA");
console.log(data);
console.log("Dumping ACTIONS");
console.log(actions);
return actions.payment.execute().then(function(payment)
{
console.log("payment.execute called");
document.querySelector('#paypal-button-container').innerText = 'Payment Complete!';
console.log("Dumping payment:");
console.log("CART: "+payment['cart']);
console.log(payment);
var values = encodeURIComponent(JSON.stringify(payment));
$.ajaxSetup({headers:{'X-CSRF-TOKEN':'{{ $token }}' } } );
ajaxRequest= $.ajax({ url: "/ajax/payment", type: "post",data:values });
ajaxRequest.done(function(response, textStatus, jqXHR)
{
var result = $.parseJSON(response);
console.log(result);
});
});
},
/ajax/payment is my capture script i'm developing at present but it does record all the data from the purchase.. hope it helps.
Related
I am trying to implement PayPal payment using a smart button with a script provided by PayPal:
<div id="smart-button-container">
<div style="text-align: center;">
<div id="paypal-button-container"></div>
</div>
</div>
<script src="https://www.paypal.com/sdk/js?client-id=MY_CLIENT_ID¤cy=CAD" data-sdk-integration-source="button-factory"></script>
<script>
function initPayPalButton() {
paypal.Buttons({
style: {
shape: 'rect',
color: 'gold',
layout: 'horizontal',
label: 'pay',
},
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{"description":"Package delivery","amount":{"currency_code":"CAD","value":1}}]
});
},
/* onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
alert('Transaction completed by ' + details.payer.name.given_name + '!');
});
}, */
onApprove: function(data) {
return fetch('/my-server/capture-paypal-transaction.php', {
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
orderID: data.orderID
})
}).then(function(res) {
return res.json();
}).then(function(details) {
alert('Transaction funds captured from ' + details.payer_given_name);
})
},
onError: function(err) {
console.log(err);
}
}).render('#paypal-button-container');
}
initPayPalButton();
</script>
I replaced the commented code with the function below that suggests one can link to a file on the server to process the returned data.
I can find no clear instruction on how this can be done with this PayPal-generated button and all the git examples relating to IPN is either outdated or has deprecated PHP code such as references to magic-quotes.
Is there an example PHP file on capturing the transaction data from a smart button?
Your example mixes a client-side actions.order.create() with a fetch to do a server-side capture. This mixing should not be done. Perform both steps from the server (or neither if not using a server-side language like PHP)
So, create two routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return only JSON data (no HTML or text). The latter one should (on success) store the payment details in your database before it does the return (particularly purchase_units[0].payments.captures[0].id, the PayPal transaction ID)
Pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
Hello I am using Express checkout for my one of project. This is first time i am working with paypal.
I have following code.
var CREATE_PAYMENT_URL = '<?php echo site_url().'/cart/' ?>create-payment';
var EXECUTE_PAYMENT_URL = '<?php echo site_url().'/cart/' ?>execute-payment';
paypal.Button.render({
env: 'sandbox', // sandbox | production
intent:'authorize',
style: {
size: 'medium', // small | medium | large | responsive
shape: 'rect', // pill | rect
tagline: false
},
funding: {
allowed: [paypal.FUNDING.CREDIT]
},
client: {
sandbox: '<?php echo $this->config->item('clientId'); ?>',
},
payment: function (data, actions) {
return paypal.request.post(CREATE_PAYMENT_URL).then(function(data) {
return data.id;
});
},
// Wait for the payment to be authorized by the customer
onAuthorize: function (data, actions) {
return paypal.request.post(EXECUTE_PAYMENT_URL, {
paymentID: data.paymentID,
payerID: data.payerID
}).then(function() {
alert('payment completes!');
});
},
}, '#paypal-button-container');
Now i want to pay through server side api call. I searched a lot but not getting proper documents for it. I don't know how to pay through server side api.
Don't know what is wrong with documents. They are never adding proper information for integration.
I am creating a application using Laravel 5.4 that require PayPal to do payments ,when i study the PayPal integration documentation i found that the REST API need 2 controller in server side name "/demo/checkout/api/paypal/payment/create/" and "/demo/checkout/api/paypal/payment/execute/", but the documentation of PayPal is blur, does anyone know what is it and the example of it?
Here is my code in frontend:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $("meta[name='csrf-token']").attr("content")
}
});
paypal.Button.render({
env: 'sandbox', // sandbox | production
// Show the buyer a 'Pay Now' button in the checkout flow
commit: true,
// payment() is called when the button is clicked
payment: function() {
// Set up a url on your server to create the payment
var CREATE_URL = '{{route('paypal.createpayment')}}';
// Make a call to your server to set up the payment
return paypal.request({
method: 'post',
url: CREATE_URL,
headers: {
'x-csrf-token': $("meta[name='csrf-token']").attr("content")
}
}).then(function(res) {
return res.paymentID;
});
},
// onAuthorize() is called when the buyer approves the payment
onAuthorize: function(data, actions) {
// Set up a url on your server to execute the payment
var EXECUTE_URL = '/demo/checkout/api/paypal/payment/execute/';
// Set up the data you need to pass to your server
var data = {
paymentID: data.paymentID,
payerID: data.payerID
};
// Make a call to your server to execute the payment
return paypal.request.post(EXECUTE_URL, data)
.then(function (res) {
window.alert('Payment Complete!');
});
}
}, '#paypal-button-container');
The documentation is on this page with example in multiple programming language : https://developer.paypal.com/docs/api/quickstart/payments/#define-payment
So on the first call to your server, you need to define the payment and create the payment.
On the second call to your server (called inside the onAuthorize function) you need to execute the payment.
I have implemented the new paypal express checkout. I want to pass my success_ipn.php URL and cancelled.php URL to checkout.js.
I have done lots of google and as well as official doc Paypal DOC.
Below is my file code:
<!DOCTYPE html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
</head>
<body>
<div id="paypal-button-container"></div>
<script>
var EXECUTE_PAYMENT_URL = 'http://example.com/success_ipn.php';
paypal.Button.render({
env: 'sandbox', // sandbox | production
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
client: {
sandbox: 'My Sandbox Client ID here.',
//production: '<insert production client id>'
},
// Show the buyer a 'Pay Now' button in the checkout flow
commit: true,
// payment() is called when the button is clicked
payment: function(data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: '0.01', currency: 'USD' }
}
]
}
});
},
// onAuthorize() is called when the buyer approves the payment
onAuthorize: function(data, actions) {
return paypal.request.post(EXECUTE_PAYMENT_URL, {
paymentID: data.paymentID,
payerID: data.payerID
}).then(function() {
window.alert('Payment Complete!');
});
}
}, '#paypal-button-container');
</script>
</body>
</html>
It's working fine, but how I can pass my IPN file URL and Cancel URL.
After do some more google on this I can get only below variables not transactions ID etc.:
paymentID: data.paymentID,
payerID: data.payerID
Please help me out this guys.
After the tried too and do google on this I have found the solution.
The paypal has deprecated the Express Checkout - NVP/SOAP after the checckout.js newest version. So, GetExpressCheckoutDetails and DoExpressCheckoutPayment is deprecated as well.
Now, all work will be done on the Rest API.
Below is update code how we can get the Payer information and transaction details in json format. After get the json response we can update our database record as well using aJax.
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<div id="paypal-button-container"></div>
<script>
var EXECUTE_PAYMENT_URL = 'http://example.com/success_checkout.php';
paypal.Button.render({
env: 'sandbox', // sandbox | production
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
client: {
sandbox: '',
//production: '<insert production client id>'
},
// Show the buyer a 'Pay Now' button in the checkout flow
commit: true,
// payment() is called when the button is clicked
payment: function(data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: '10', currency: 'USD' },
custom: 'custom value here'
}
]
}
});
},
onAuthorize: function(data, actions) {
return actions.payment.get().then(function(payment) {
//debugger;
console.log(payment);
var txn_id = payment.cart;
var bookID = payment.transactions[0].custom;
var currency = payment.transactions[0].amount["currency"];
var amount = payment.transactions[0].amount["total"];
var payerID = payment.payer.payer_info["payer_id"];
var pstatus = payment.payer.status;
var successUrl = EXECUTE_PAYMENT_URL+'?txn_id='+txn_id+'&bookID='+bookID+'¤cy='+currency+'&amount='+amount+'&payerID='+payerID+'&pstatus='+pstatus;
//console.log(newUrl);
window.location.replace(successUrl);
});
},
onCancel: function(data, actions) {
var cancelUrl = "http://example.com/cancelled.php";
//console.log(newUrl);
window.location.replace(cancelUrl);
}
}, '#paypal-button-container');
</script>
And you will get response in the success_checkout.php like below:
<?php
echo '<pre>' print_r($_REQUEST);
// do your stuff here
header('Location: thanks.php');
?>
Hope this will help to other developers.
EDIT:
As #bluepnume stated probably this is a bug and would be fixed later.
In my case I did the same thing (create payment / execute payment) but on server side with the REST API without using checkout.js and now everything works fine.
The only difference is that I'm redirecting the client to PayPal (with $payment->getApprovalLink()) instead of using the on-site lightbox generated by checkout.js.
Original question:
I integrated PayPal Express Checkout with a Basic Client Integration.
Everything seems fine. The payment completes smoothly and I can view the payment as completed/approved from both Rest API request and Seller's Account (Sandbox).
However the payment is not completed even after successful Execute. I try to make a refund from the API after order cancellation but after reading Payment data successfully I can't receive and Related Resources in payment's transactions.
JS code (works fine):
paypal.Button.render({
env: $form.find('[name="env"]').val(),
client: {
sandbox: $form.find('[name="client_id"]').val(),
production: $form.find('[name="client_id"]').val()
},
locale: 'it_IT',
commit: true, // Optional: show a 'Pay Now' button in the checkout flow
payment: function() {
var env = this.props.env;
var client = this.props.client;
return paypal.rest.payment.create(env, client, {
transactions: [
{
custom: $form.find('[name="custom"]').val(),
amount: {
total: $form.find('[name="subtotal"]').val(),
currency: $form.find('[name="currency_code"]').val()
},
description: $form.find('[name="item_name"]').val(),
}
],
redirect_urls: {
"return_url": $form.find('[name="return"]').val(),
"cancel_url": $form.find('[name="notify_url"]').val()
}
});
},
onAuthorize: function(data, actions) {
return actions.payment.execute().then(function() {
actions.payment.get().then(function(data) {
pjQ.$.post($form.find('[name="notify_url"]').val(), data).done(function (data) {
return actions.redirect();
});
});
});
},
onCancel: function(data, actions) {
return actions.redirect();
}
}, '#paypal-button');
PHP code:
$payment = \PayPal\Api\Payment::get($paymentId, $apiContext); // It's ok
$transactions = $payment->getTransactions(); // It's ok
$relatedResources = $transactions[0]->getRelatedResources(); // Empty...
// I can't use the code below as $relatedResources is empty
$sale = $relatedResources[0]->getSale();
$saleId = $sale->getId();
$sale = new \PayPal\Api\Sale();
$sale->setId($saleId);
$refundedSale = $sale->refundSale($refundRequest, $apiContext);
Any ideas?
That's a known issue, and a fix is going out soon. See https://github.com/paypal/paypal-checkout/issues/143.