DOMException: Failed to execute 'show' on 'PaymentRequest': PaymentRequest.show() - javascript

I came across Javascript's Payment API and thought of understanding it. So, I have generated a sample code for the API to check the working. But I am getting this error:
DOMException: Failed to execute 'show' on 'PaymentRequest': PaymentRequest.show() requires either transient user activation or delegated payment request capability
while using the code. No idea what is wrong with it
Here is the sample code I am using:
if (window.PaymentRequest) {
// Create a payment method object for the supported payment methods
const methodData = [{
supportedMethods: ['basic-card'],
data: {
supportedNetworks: ['visa', 'mastercard'],
supportedTypes: ['debit', 'credit']
}
}];
// Create the payment details object with the total amount
const details = {
total: {
label: 'Total amount',
amount: {
currency: 'USD',
value: '50.00'
}
}
};
// Create the payment request object
const paymentRequest = new PaymentRequest(methodData, details);
// Show the payment UI to the user and wait for their response
paymentRequest.show()
.then(response => {
console.log("Response: ", response)
})
.catch(error => {
console.error('Payment request failed: ', error);
});
} else {
console.error('Payment Request API is not supported');
}

Related

Paypal Checkout - Payment always on pending

Since three days i am trying to get the Paypal Checkout to work but i always have the problem that the order is created and the money in gone from the buying account but not reaching the payee account.
So here is my setup:
The Smart Buttons integeration in JavaScript:
paypal.Buttons({
env: enviroment,
// Set up the transaction
createOrder: function() {
let formData = new FormData();
formData.append('bookingId', bookingId);
return fetch (url_createOrder, {
method: 'POST',
body: formData
}).then(response => {
console.log(response);
return response.json()
})
.then(function(res) {
console.log(res);
return res.result.id;
});
},
// Finalize the transaction
onApprove: function(data, actions) {
console.log(data);
// This function captures the funds from the transaction.
return actions.order.capture().then(function(details) {
console.log(details);
// This function shows a transaction success message to your buyer
// window.location.href = 'danke.php';
});
}
}).render('#paypal-button-container');
As you can see the createOrder starts a AJAX call to this script:
[...]
$client = new PayPalHttpClient($environment);
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = self::buildRequestBody($price);
// 3. Call PayPal to set up a transaction
$response = $client->execute($request);
echo json_encode($response, JSON_PRETTY_PRINT);
// 4. Return a successful response to the client.
return $response;
}
private static function buildRequestBody($price) {
return array(
'intent' => 'CAPTURE',
'application_context' => array(
'brand_name' => 'Example',
'cancel_url' => 'http://localhost/example/abbruch.php',
'return_url' => 'http://localhost/example/danke.php'
),
'purchase_units' => array(
0 => array(
'reference_id' => 'example_addr',
'description' => 'example Address',
'amount' => array(
'currency_code' => 'EUR',
'value' => $price
)
)
)
);
[...]
Everything works so far to this point. I get a OrderId back which i return to the AJAX call and then i am am able to insert credentials and pay the given price.
When i finish the payment the onApprove of the smart buttons in the JS file get called back and i also get the correct response of that actions.order.capture():
{create_time: "2020-08-14T19:37:59Z", update_time: "2020-08-14T19:38:20Z", id: "6FP46164U47878440", intent: "CAPTURE", status: "COMPLETED", …}
create_time: "2020-08-14T19:37:59Z"
id: "6FP46164U47878440"
intent: "CAPTURE"
links: [{…}]
payer:
address:
country_code: "DE"
__proto__: Object
email_address: "sb-ughwh2901918#personal.example.com"
name: {given_name: "John", surname: "Doe"}
payer_id: "8Z5RM2ERW6VTL"
__proto__: Object
purchase_units: [{…}]
status: "COMPLETED"
update_time: "2020-08-14T19:38:20Z"
__proto__: Object
Afterwards the money is gone from the buyer account but it says "pending", here a screenshot (but in german)
payment_is_pending.png
On the seller account i can´t select anything like "approve". I found an example of the paypal checkout api which works similar and tried to copy it into my code but yeah... same story.
Then i thought maybe the problem is the seller sandbox account, but if i try it which an sandbox account created and given by a paypal tutorial is says pending as well.
Please, help!
The payments are pending because there is no sandbox account with the email sb-2xact2876961#business.example.com confirmed, so the payments are in an unclaimed state. Pending unclaimed payments will be automatically returned after 30 days if left unclaimed.
To claim the payments, the email sb-2xact2876961#business.example.com must be confirmed on a sandbox account, via https://www.sandbox.paypal.com/businessprofile/settings/email and https://developer.paypal.com/developer/notifications/

how to properly use Stripe api for saved card on client side

I am currently working with Stripe API. I was able to use one time payment properly, and save credit card correctly as well as process;
However, I was stuck on the 3D secure(2nd auth) for saved card on client side. I had search out the website with no success. And the official doc https://stripe.com/docs/payments/save-and-reuse#web-create-payment-intent-off-session seems with little information about using saved card on client side. Or probably I just don't understand it. Hopefully someone can guide me out with correct practice.
Below it's the critical part of codes, it currently works with one time payment and 2nd auth stripe pop out.
NOTE: I was able to create a charge based on the information from each individual card from $saved_cards in my server, however it would not trig the 3d secure hence it will always failed with cards that requires 2nd authentication
backend.php
\Stripe\Stripe::setApiKey(env('STRIPE_SECRET'));
$intent = \Stripe\PaymentIntent::create([
'amount' => $payment * 100,
'currency' => 'usd',
]);
if (!empty(Auth::user()->stripe_id)) { //all saved card info
$saved_cards = \Stripe\PaymentMethod::all([
'customer' => Auth::user()->stripe_id,
'type' => 'card',
]);
}
return view('cart.preview', $items)->with('saved_cards', $saved_cards)->with('client_secret', $intent->client_secret);
Client.js
// this is for one time payment
var payment_method = {
card: card,
billing_details: {
name: "name"
}
};
stripe.confirmCardPayment( "{{ $client_secret }}", {
payment_method: payment_method, // <= I believe this is the place I can use the saved card?
}).then(function (result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
}
}
});
/*****************************************************************************/
Update for solution based on answer suggestion:
Disclaimer: this might be a bad practice since the secret switch happens on the frontend side. But you get the idea.
In order to use your payment_method id, you also have to attach your customer id, which happens in the backend side. So for my case I created another savedCard_intent in my backend and pass it to frontend for handle the saved card specifically.
$savedCard_intent = \Stripe\PaymentIntent::create([
'customer' => Auth::user()->stripe_id,
'amount' => $payment * 100,
'currency' => 'usd',
]);
pass it to frontend with('saved_secret' ,$savedCard_intent->client_secret);
Combine all of them together I have code like the following:
newBackend.php
\Stripe\Stripe::setApiKey(env('STRIPE_SECRET'));
$new_intent = \Stripe\PaymentIntent::create([
'amount' => $payment * 100,
'currency' => 'usd',
]);
$savedCard_intent = \Stripe\PaymentIntent::create([
'customer' => Auth::user()->stripe_id,
'amount' => $payment * 100,
'currency' => 'usd',
]);
if (!empty(Auth::user()->stripe_id)) { //all saved card info
$saved_cards = \Stripe\PaymentMethod::all([
'customer' => Auth::user()->stripe_id,
'type' => 'card',
]);
}
return view('cart.preview', $items)->with('saved_cards', $saved_cards)->with('new_secret', $new_intent->client_secret)->with('saved_secret', $savedCard_intent->client_secret);
newClient.js
// this is for one time payment
var payment_method = {
card: card,
billing_details: {
name: "name"
}
};
var secret = (Some conditions here) ? "{{$new_secret}}" : "{{$saved_secret}}";
stripe.confirmCardPayment( secret, {
payment_method: (Some conditions here) ? payment_method : saved_payment_method.id,
}).then(function (result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
}
}
});
You are correct. You would use the PaymentMethod's id (pm_******) like so:
stripe.confirmCardPayment( "{{ $client_secret }}", {
payment_method: payment_method.id,
}). then( ... )
Documented here: https://stripe.com/docs/js/payment_intents/confirm_card_payment#stripe_confirm_card_payment-data-payment_method
You can also pass a PaymentMethod object if you're generating one on the client side, but that's not likely the approach you're looking for.

There are no accepted cards available for use with this merchant - Google Pay

I am trying to integrate Google Pay web into my website but when i click "pay with googlepay" its shows the below error:
There are no accepted cards available for use with this merchant.
When i read documentation it says you can add example as merchant for testing, I just wanted to use test environment but still its not working.
Here is the code that i am using:
const allowedAuthMethods = ['PAN_ONLY','CRYPTOGRAM_3DS'] ;
const baseCardPaymentMethod = {
type: 'CARD',
parameters: {
allowedCardNetworks: allowedNetworks,
allowedAuthMethods: allowedAuthMethods
}
};
const googlePayBaseConfiguration = {
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [baseCardPaymentMethod]
};
/**
* Holds the Google Pay client used to call the different methods available
* through the API.
* #type {PaymentsClient}
* #private
*/
let googlePayClient;
/**
* Defines and handles the main operations related to the integration of
* Google Pay. This function is executed when the Google Pay library script has
* finished loading.
*/
function onGooglePayLoaded() {
googlePayClient = new google.payments.api.PaymentsClient({
environment: 'TEST'
});
googlePayClient.isReadyToPay(googlePayBaseConfiguration)
.then(function(response) {
if(response.result) {
createAndAddButton();
} else {
alert("Unable to pay using Google Pay");
}
}).catch(function(err) {
console.error("Error determining readiness to use Google Pay: ", err);
});
}
/**
* Handles the creation of the button to pay with Google Pay.
* Once created, this button is appended to the DOM, under the element
* 'buy-now'.
*/
function createAndAddButton() {
const googlePayButton = googlePayClient.createButton({
// currently defaults to black if default or omitted
buttonColor: 'default',
// defaults to long if omitted
buttonType: 'long',
onClick: onGooglePaymentsButtonClicked
});
document.getElementById('buy-now').appendChild(googlePayButton);
}
/**
* Handles the click of the button to pay with Google Pay. Takes
* care of defining the payment data request to be used in order to load
* the payments methods available to the user.
*/
function onGooglePaymentsButtonClicked() {
const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'example',
gatewayMerchantId: 'exampleGatewayMerchantId'
}
};
const cardPaymentMethod = {
type: 'CARD',
tokenizationSpecification: tokenizationSpecification,
parameters: {
allowedCardNetworks: ['VISA','MASTERCARD'],
allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS'],
billingAddressRequired: true,
billingAddressParameters: {
format: 'FULL',
phoneNumberRequired: true
}
}
};
const transactionInfo = {
totalPriceStatus: 'FINAL',
totalPrice: '123.45',
currencyCode: 'USD',
countryCode: 'US'
};
const merchantInfo = {
merchantId: '01234567890123456789', //Only in PRODUCTION
merchantName: 'Example Merchant Name'
};
const paymentDataRequest = Object.assign({}, googlePayBaseConfiguration, {
allowedPaymentMethods: [cardPaymentMethod],
transactionInfo: transactionInfo,
merchantInfo: merchantInfo
});
googlePayClient
.loadPaymentData(paymentDataRequest)
.then(function(paymentData) {
processPayment(paymentData);
}).catch(function(err) {
// Log error: { statusCode: CANCELED || DEVELOPER_ERROR }
});
}
function processPayment(paymentData) {
// TODO: Send a POST request to your processor with the payload
// https://us-central1-devrel-payments.cloudfunctions.net/google-pay-server
// Sorry, this is out-of-scope for this codelab.
return new Promise(function(resolve, reject) {
// #todo pass payment token to your gateway to process payment
const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
console.log('mock send token ' + paymentToken + ' to payment processor');
setTimeout(function() {
console.log('mock response from processor');
alert('done');
resolve({});
}, 800);
});
} ```
There are no accepted cards available for use with this merchant.
This message means that the current Google user doesn't have any cards that are compatible with the payment options that the merchant has provided. Specifically allowedCardNetworks and allowedAuthMethods.
Here is a JSFiddle that I created based on your snippet: https://jsfiddle.net/aumg6ncb/
This is what I get back after clicking on the button:
If You are using Testing mode:-
I think You used testing card on your Chrome browser or Google Wallet
When testing Google Pay you should have a real card saved in your Chrome browser or Google Wallet, and have your test API keys/test Google Pay environment active. The real card does not get charged, and Google passes a test card during the checkout flow instead of a real card. Our normal test cards do not work with Google Pay when the user tries to save them in Chrome

paypal checkout button get json response in javascript

In the paypal API reference page it says after creating a payment it will return a response. I would like to use the transaction information after payment is completed, but I'm not sure how to obtain this response json from the basic integration scenario here. After going through the documentation, I don't see where I can get this response. Am I missing a missing a option here? Thanks in advance.
The following is my code
paypal.Button.render({
// Set your environment
env: 'sandbox', // sandbox | production
// Pass the client ids to use to create your transaction on sandbox and production environments
client: {
sandbox: 'removed for security', // from https://developer.paypal.com/developer/applications/
production: 'removed for security' // from https://developer.paypal.com/developer/applications/
},
// Pass the payment details for your transaction
// See https://developer.paypal.com/docs/api/payments/#payment_create for the expected json parameters
payment: function() {
return paypal.rest.payment.create(this.props.env, this.props.client, {
transactions: [
{
amount: {
total: total,
currency: 'USD'
},
custom: purchaseOrderNumber
}
]
});
},
// Display a "Pay Now" button rather than a "Continue" button
commit: true,
// Pass a function to be called when the customer completes the payment
onAuthorize: function(data, actions) {
console.log("data", data);
console.log("actions", actions);
return actions.payment.execute().then(function() {
console.log('The payment was completed!');
//use transaction information from json response here
});
},
// Pass a function to be called when the customer cancels the payment
onCancel: function(data) {
console.log('The payment was cancelled!');
}
}, '#paypal-button');
EDIT:
console results for data
{
"paymentToken":"EC-8T213183GM917341N",
"payerID":"784ARKSZGWBPG",
"paymentID":"PAY-00M809553A479072XLEBN4RI",
"intent":"sale",
"returnUrl":"https://www.sandbox.paypal.com/?paymentId=PAY-00M809553A479072XLEBN4RI&token=EC-8T213183GM917341N&PayerID=784ARKSZGWBPG"
}
console results for actions
{
"payment":{}
}
//see below for console screenshot
EDIT2:
request to paypal framework and response
It would appear that The last picture is the response that I actually need. Is there a way to obtain this data from a basic paypal button?
Add a parameter to actions.payment.execute().then() to catch the response
paypal.Button.render({
// Set your environment
env: 'sandbox', // sandbox | production
// Pass the client ids to use to create your transaction on sandbox and production environments
client: {
sandbox: 'removed for security', // from https://developer.paypal.com/developer/applications/
production: 'removed for security' // from https://developer.paypal.com/developer/applications/
},
// Pass the payment details for your transaction
// See https://developer.paypal.com/docs/api/payments/#payment_create for the expected json parameters
payment: function() {
return paypal.rest.payment.create(this.props.env, this.props.client, {
transactions: [
{
amount: {
total: total,
currency: 'USD'
},
custom: purchaseOrderNumber
}
]
});
},
// Display a "Pay Now" button rather than a "Continue" button
commit: true,
// Pass a function to be called when the customer completes the payment
onAuthorize: function(data, actions) {
return actions.payment.execute().then(function(param) {
console.log('The payment was completed!');
//param is the json response
});
},
// Pass a function to be called when the customer cancels the payment
onCancel: function(data) {
console.log('The payment was cancelled!');
}
}, '#paypal-button');
The setup seems all good, all you need now is to decide what and how you want to handle your response.
In the onAuthorize function you can do something like (github paypal checkout button) this for all of your aproved sales (check for data.status to be approved (credit card) or created (for payment with paypal), then you should have a data.payer with all the info):
jQuery.post('/my-api/execute-payment', { paymentID: data.paymentID, payerID: data.payerID });
.done(function(data) { /* Go to a success page */ })
.fail(function(err) { /* Go to an error page */ });
or use directly the data json object in the function.

Inserting an event with the nodejs google calendar API returns 400: "Missing end time"

I am trying to insert events via the Google Calendar API with a service account. The goal is to have one calendar that all users view: a server-to-server setup.
As of now, I can properly call the calendar API and list the events on said calendar:
var moment = require("moment"),
googleapis = require("googleapis"),
googleCal = googleapis.calendar("v3");
serviceEmail = "********#developer.gserviceaccount.com",
serviceKeyFile = "./key.pem";
var authClient = new googleapis.auth.JWT(
serviceEmail,
serviceKeyFile,
null,
["https://www.googleapis.com/auth/calendar"]
);
authClient.authorize(function (err, tokens) {
if (err) {
console.log(err);
} else {
googleCal.events.list({
auth: authClient,
calendarId: "********#gmail.com",
fields: {
items: ["end","start","summary"]
}
}, function (err, CL) {
if (err) {
console.log(err);
} else {
console.log(CL);
}
});
}
})
This properly returns a JSON object that lists all the different objects on the calendar. However, when I try to insert an event directly below the googleCal.events.list call:
googleCal.events.insert({
auth: authClient,
calendarId: "primary",
resources: {
start: {
dateTime: "2014-07-23T18:25:00.000-07:00",
timeZone: "America/New_York"
},
end: {
dateTime: "2014-07-23T19:25:00.000-07:00",
timeZone: "America/New_York"
},
summary: "winning # life",
description: "winning # life description"
}
}, function (err, something) {
if (err) {
console.log(err);
} else {
console.log(something);
// do something else
}
})
The following 400 is returned:
{ errors:
[ { domain: 'global',
reason: 'required',
message: 'Missing end time.' } ],
code: 400,
message: 'Missing end time.'}
How do I go about fixing this? The authorization is clearly working—I know because I've used up my unauthorized requests for the day and because I can list all the events. I have also specified an endTime. Why is the google calendar API telling me that I haven't?
I think the problem is in the keyword "resources" on line 4 of your second snippet. Based on the documentation, it should be a "resource":
* #param {object} params.resource - Request body data

Categories

Resources