Paypal webhooks events are not triggered in sandbox - paypal

Hello I am using the following setup
Created paypal merchant and customer sandbox accounts
Configured paypal REST API app
Added a webhook url to my server and have validated that it works using the webhook simulator
Used the Express Checkout javascript implementation found here
I am able to make successful payments when viewing the notifications in sandbox but no webhook is ever triggered???
Below is a sample of my javascript implementation that I have used, please not that it's embedded in a coldfusion script file hence the use hashtags.
`
var items = #paypalItems#;
// Render the PayPal button
paypal.Button.render({
env: '#application.config.paypal.bSandbox ? "sandbox" : "production"#', // sandbox | production
commit: true,
//style the button
style: {
label: 'pay'
},
// PayPal Client IDs - replace with your own
client: {
sandbox: '#application.config.paypal.sandbox_key#',
production: '#application.config.paypal.live_key#'
},
// Wait for the PayPal button to be clicked
payment: function(data, actions) {
// Make a client-side call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [{
amount: {
total: #trim(numberFormat( application.oCart.getTotal(bDiscount=1,bShipping=1) , "99999999.99" ))#,
currency: "AUD",
details: {
subtotal: #trim(numberFormat( application.oCart.getTotal() - application.oCart.getAmountGST( amount=application.oCart.getTotal(bDiscount=1), addGST=false ), "99999999.99" ))#,
tax: #trim(numberFormat(application.oCart.getAmountGST( amount=application.oCart.getTotal(bDiscount=1), addGST=false ), "99999999.99" ))#,
shipping: #trim(numberFormat( application.oCart.oShipping.getCartShippingAmount(country=session.fcbshoppingCart.order.shippingCountry), "99999999.99" ))#
}
},
invoice_number: "#orderNumber#",
item_list: {
items: items,
shipping_address: {
recipient_name: "#session.fcbshoppingCart.customer.firstName# #session.fcbshoppingCart.customer.lastName#",
line1: "#session.fcbshoppingCart.order.shippingAddress1#",
line2: "#session.fcbshoppingCart.order.shippingAddress2#",
city: "#session.fcbshoppingCart.order.shippingSuburb#",
country_code: "#paypalCountryCode#",
postal_code: "#session.fcbshoppingCart.order.shippingPostCode#",
state: "#session.fcbshoppingCart.order.shippingState#"
}
}
}]
}
});
},
// Wait for the payment to be authorized by the customer
onAuthorize: function(data, actions) {
console.log( "Paypal Authorize:", data );
// Execute the payment
return actions.payment.execute().then(function(payment) {
console.log( "Paypal Response:", payment );
//payment has been accepted so we can now generate an order
$.ajax({
type: "get",
url: "/apps/paypal/createOrder.cfm",
data: {
transactionNumber: "#orderNumber#",
payPalPaymentId: data.paymentID
},
dataType: "json",
success: function( res ) {
console.log('edharry create order data', res);
if( res.BPAYMENTPROCEED ) {
$('##paypal-message').addClass("show success").text('Payment Successfully Complete!');
//lets redirect to the checkout success page.
window.location.href = window.location.origin + '/shop/checkout/confirmation?productOrder=' + res.PRODUCTORDER.OBJECTID;
} else {
//need to handle a failed transaction
$('##paypal-message').addClass("show failure").text('Payment did not complete on server!');
}
},
error: function() {
//lets show an error
$('##paypal-message').addClass("show failure").text('Payment did not complete on server!');
}
})
$('##paypal-message').addClass("show success").text('Payment Successfully Complete!');
});
},
onCancel: function(data) {
console.log('The payment was cancelled!');
}
}, '##paypal-button-container');`

This is an ongoing issue with Paypal. They are aware of this issue and are currently working to resolve this.

Related

Mobile iDEAL payments not being captured

I have been struggling with this issue for some time now. Even created a support ticket at my Devs PayPal portal, but even the devs seem to not know what exactly is going wrong. Therefor, I'm asking it here, hoping someone can help me.
The issue: I have a website where people have to check out using iDEAL. To process these iDEAL payments, I use PayPal. Everything works great on desktop, but for some reason, the payments are not being captured when I use my iPhone to pay. I even checked it on different devices, but the issue remains.
What happens when I use my dekstop to pay: after selecting the desired bank, I get redirected to the payment page of my bank. I scan the QR code, make the payment, and get redirected to my own website where I store everything in the DB / show success message. The money has been taken out of my bank and added to my PayPal account. (the payment has been captured)
What happens when I use my phone to pay: after selecting the desired bank, I get redirected to the App to make the payment. Once done so, I get redirected to a 'Thank you' page from PayPal themselfs. The money has been taken out of my bank account, but NOT added to my PayPal account, instead it gone missing (and probably gets refunded by PayPal). - the payment has NOT been captured.
The above is whenever I'm not using the sandbox. However, I'm in the sandbox, the same thing happens: desktop payments are being captured, mobile payments are NOT being captured.
When I check the API calls in my PayPal Dev dashboard, I can see when I'm paying via mobile that the order has been created, but never captured. But the order is being created and captured when I use my desktop.
Any help would be appreciated.
This is the part of my code
// CREATE GLOBAL VARS
var invoice_id = '<?php echo $db_invoice_id; ?>';
function submit_database(transaction_id, transaction_amount, transaction_status) {
// DEBUG
console.log('---BELOW PAYPAL FUNCTION---');
console.log(invoice_id);
console.log(transaction_id);
console.log(transaction_amount);
console.log(transaction_status);
$.ajax({
type: "POST",
url: "/data/betalingen/herinnering/",
data: {invoice_id: invoice_id, transaction_id: transaction_id, transaction_amount: transaction_amount, transaction_status: transaction_status},
success: function(data,textStatus,jqXHR){ start_processingIDEALPayment(data,textStatus,jqXHR); }
});
function start_processingIDEALPayment(data,textStatus,jqXHR) {
// DEBUG
//alert(data);
console.log(data);
if (data == 'success') {
$('.access-purchase .actions').hide();
$('.access-purchase .content-inner .description').removeClass('alert-danger');
$('.access-purchase .content-inner .description').addClass('alert-success');
$('.access-purchase .content-inner .description').html('<i class="fa-solid fa-check"></i> Wij hebben je betaling succesvol ontvangen. De pagina wordt ieder moment ververst, waarna je toegang zult hebben tot de stream.');
setTimeout(function (){
//Reload page
location.reload();
}, 5000);
}
}
}
paypal.PaymentFields({
fundingSource: paypal.FUNDING.IDEAL,
fields: {
// PREFILL NAME FIELD
name: {
value: "<?pho echo $db_name; ?>",
},
}
})
.render("#ideal-fields");
paypal.Buttons({
fundingSource: paypal.FUNDING.IDEAL,
style: { label: "pay", },
createOrder: (data, actions) => {
return actions.order.create({
"purchase_units": [{
"amount": {
"currency_code": "EUR",
"value": "<?php echo $next_amount_to_pay; ?>",
"breakdown": {
"item_total": {
"currency_code": "EUR",
"value": "<?php echo $next_amount_to_pay; ?>"
}
}
},
"items": [
{
"name": "Betaling voor factuur: #<?php echo $db_invoice_id; ?>",
"unit_amount": {
"currency_code": "EUR",
"value": "<?php echo $next_amount_to_pay; ?>"
},
"quantity": "1"
},
],
}]
});
},
onApprove(data, actions) {
return actions.order.capture().then(function(orderData) {
// DEBUG
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
// CREATE VARS
var transaction = orderData.purchase_units[0].payments.captures[0];
var transaction_id = transaction.id;
var transaction_amount = transaction.amount.value;
var transaction_status = transaction.status;
// DEBUG
console.log(transaction_id);
console.log(transaction_amount);
console.log(transaction_status);
// SUBMIT TO DB
submit_database(transaction_id, transaction_amount, transaction_status);
// SHOW MESSAGE TO USER
$('.box.invoice-payment').hide(); // HIDE PAYMENT FORM
$('#openPaymentHandler').hide(); // HIDE PAYMENT FORM
$('#payment-callback').removeClass('alert-danger');
$('#payment-callback').addClass('alert-success');
$('#payment-callback').html('<i class="fa-solid fa-check"></i> Wij hebben je betaling in goede orde ontvangen.');
$('#payment-callback').show();
setTimeout(function (){
//Reload page
location.reload();
}, 3500);
});
},
onCancel(data, actions) {
// CANCELED
//DEBUG
console.log(`Order Canceled - ID: ${data.orderID}`);
var transaction_id = data.orderID;
var transaction_amount = '0.00';
var transaction_status = 'cancelled';
// SUBMIT TO DB
submit_database(transaction_id, transaction_amount, transaction_status);
// SHOW MESSAGE TO USER
$('#payment-callback').removeClass('alert-success');
$('#payment-callback').addClass('alert-danger');
$('#payment-callback').html('<i class="fa-regular fa-circle-xmark"></i> De betaling is afgebroken of mislukt.');
$('#payment-callback').show();
},
onError(err) {
// ERROR
// DEBUG
console.error(err);
if (err == 'Error: Detected popup close') {
var errorMsg = '<i class="fa-regular fa-circle-xmark"></i> De betaling is mislukt, omdat het betaalvenster is afgesloten.';
} else {
var errorMsg = '<i class="fa-regular fa-circle-xmark"></i> De betaling is afgebroken of mislukt.';
}
// SHOW MESSAGE TO USER
$('#payment-callback').removeClass('alert-success');
$('#payment-callback').addClass('alert-danger');
$('#payment-callback').html(errorMsg);
$('#payment-callback').show();
alert(err);
},
}).render("#ideal-btn");

Create Payment Request API

I am trying to integrate the Payment Request API for the Google Pay for Payments using javascript but my code returns a PaymentRequest is not defined error.
Here is my code.
CODE:
const supportedInstruments = [
{
supportedMethods: ['https://tez.google.com/pay'],
data: {
pa: 'abc#gmail.com',
pn: 'abc',
tr: '1234ABCD', // your custom transaction reference ID
url: 'http://url/of/the/order/in/your/website',
mc: '1234', // your merchant category code
tn: 'Purchase in Merchant',
},
}
];
const details = {
total: {
label: 'Total',
amount: {
currency: 'INR',
value: '10.01', // sample amount
},
},
displayItems: [{
label: 'Original Amount',
amount: {
currency: 'INR',
value: '10.01',
},
}],
};
let request = null;
try {
request = new PaymentRequest(supportedInstruments, details);
}
catch (e) {
console.log('Payment Request Error: ' + e.message);
return;
}
if (!request) {
console.log('Web payments are not supported in this browser.');
return;
}
Error Message:
Payment Request Error: PaymentRequest is not defined
Sounds to me like you are testing it in an older browser that simply doesn't support it. Browser support is pretty good these days, but not universal. You just need to do a simple bit of feature detection and wrap your code in an if statement to check the browser supports it:
if (window.PaymentRequest) {
// your payment request code here
}

braintree.paypalCheckout.create add dynamical amount to the paypal button

I use HostedFields for credit card and paypal web for paypal.
So inside of braintree.client.create i have braintree.hostedFields.create and braintree.paypalCheckout.create.
Code example of paypal:
braintree.paypalCheckout.create({
client: clientInstance
}, function (paypalCheckoutErr, paypalCheckoutInstance) {
if (paypalCheckoutErr) {
console.error('Error creating PayPal Checkout:', paypalCheckoutErr);
return;
}
paypal.Button.render({
env: 'sandbox',
commit: true,
buttonStyle: {
color: 'blue',
shape: 'rect',
size: 'medium'
},
payment: function () {
return paypalCheckoutInstance.createPayment({
flow: 'checkout',
locale: ''+langanalytics+'',
amount: '10.00',
currency: 'EUR'
});
},
onAuthorize: function (data, actions) {
return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
document.getElementById("paynonce").value = payload.nonce;
document.getElementById("paymentform").submit();
});
},
onCancel: function (data) {
console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2));
},
onError: function (err) {
console.error('checkout.js error', err);
}
}, '#paypal-button').then(function () {
});
});
The problem is according to my client he want a single page checkout, where the amount get generated dynamically.
For example if someone change the country or payment method the price can change for some €. A click EventListener start the calculation and changes the total sum in real time.
My Problem:
I cant change the amount of my paypal intialization of this part:
return paypalCheckoutInstance.createPayment({
flow: 'checkout',
locale: ''+langanalytics+'',
amount: '10.00',
currency: 'EUR'
});
Is there any way to update the amount outsite of the function as soon as total sum changes (i have full control of this).
I already tried to intialize the whole braintree.client.create new on total sum change but i get errors from hosted fields a instance is already created and for paypal i recieve multiple buttons.

PayPal client-side? What is minimum code required for multiple buttons?

I'm working with .Net, trying to implement multiple buttons.
I'm getting an answer from PayPal (payment id, payer-id, etc.), but everything is client-side. How can I check the payment on server-side?
Do I need to implement all this code for each button?
<script>
paypal.Button.render({
env: 'production', // Optional: specify 'sandbox' environment
client: {
sandbox: 'xxxxxxxxx',
production: 'xxxxxxxxx'
},
payment: function() {
var env = this.props.env;
var client = this.props.client;
return paypal.rest.payment.create(env, client, {
transactions: [
{
amount: { total: '1.00', currency: 'USD' }
}
]
});
},
commit: true, // Optional: show a 'Pay Now' button in the checkout flow
onAuthorize: function(data, actions) {
// Optional: display a confirmation page here
return actions.payment.execute().then(function() {
// Show a success page to the buyer
});
}
}, '#paypal-button');
</script>
To get the information on the server side, you can pass data.paymentID to your server side and use it to make a REST call to paypal: https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/advanced-payments-api/show-payment-details/
To render multiple buttons you do need to call paypal.Button.render() multiple times, but if you need to you can do this in a for loop, or something.

Stuck with integration of Paypal Express Checkout ( Basic integration checkout.js version 4.0.0)

I'm trying to integrate Paypal Express Checkout into simple Shopping Cart. There are different ways to do that. Paypal recommends to choose between Basic or Advanced integration and version 4.0 of checkout.js (with REST API). So far so good.
I created Paypal App in my Paypal account to get credentials and start testing it.
The test was OK, but there are some misunderstandings here.
Checkout.js send the amount ( 1.00 ) and currency ( EUR ) to the Paypal servers via REST API (along with my credentials). And if the payment is finished OK - callback function onAuthorize is triggered and there are two parameters with response (data and actions). Well, here I call my own AJAX function to write transaction response data in my database. BUT... I get here only PaymentID and PayerID of the paid transaction?!! And if I want to search later into web interface of paypal.com - there is no such thing as PaymentID. There is only TransactionID ??? How to get other transaction details in the response in onAutorize callback function? How can I get TransactionID here to write down in my database? May be here I have to call Paypal API, or have to implement Paypal IPN (instant payment notification )? BUT how to call IPN API, if I don't have TransactionID :)
<div style="width: 906px; text-align: right; height: 100px;
margin-top: 50px;">
<div id="paypal-button"></div>
</div>
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
paypal.Button.render({
env: 'production', // Optional: specify 'sandbox' environment
style: {
size: 'medium',
shape: 'rect'
},
client: {
sandbox: 'xxx-my-credentials-xxx',
production: 'xxx-my-credentials-xxx'
},
payment: function() {
var env = this.props.env;
var client = this.props.client;
return paypal.rest.payment.create(env, client, {
transactions: [
{
amount: { total: '1.00', currency: 'EUR' }
}
]
});
},
commit: true, // Optional: show a 'Pay Now' button in the checkout flow
onAuthorize: function(data, actions) {
// Optional: display a confirmation page here
var EXECUTE_PAYMENT_URL = 'payment-process.php';
paypal.request.post(EXECUTE_PAYMENT_URL, { paymentID: data.paymentID, payerID: data.payerID, transactionID: data.transactionID, data: data }) .then(function(data) { }) .catch(function(err) { });
return actions.payment.execute().then(function() {
// Show a success page to the buyer
});
}
}, '#paypal-button');
</script>
To read the information from the transaction you need to call and save data JSON in database
return actions.payment.execute().then(function() {
actions.payment.get().then(function(data) {
if(data.state === 'approved'){
console.log(data);
var transactionId = data.id;
alert("Transaction ID: "+ transactionId + " \n State: " +data.state);
}else{
console.log(data);
}
});
});