I have integrated Stripe for payments.
I managed to save a card by obtaining the token, created the customer, and associated the token with the customer.
Now I am trying to make a backend (node) side payments using this code:
const createCharge = await stripe.charges.create({
amount,
currency: 'eur',
customer: user.stripeCustomerId,
card: cardId,
description: `userId: ${user._id}`,
});
If the card does not require authentication it works perfectly while if authentication is required it obviously fails with the error: authentication_required.
I tried to add authentication with 3d secure in-app but without success, this is what I tried but I always get errors and no authentication is done
const { paymentIntent, error } = await confirmPayment(clientSecret.client_secret, {
payment_method_options:{
"card": {
"installments": null,
"network": null,
"request_three_d_secure": "any"
}
},
type: 'Card',
cardDetails: this.props.cardList[0].cardId,
payment_method:'creditCard',
setupFutureUsage: 'OffSession',
});
Does anyone have any idea what I'm doing wrong?
Thanks!
Related
I am trying to initiate an MA transaction using easy paisa api. The response error I get after executing the following code is as follows.
'RESPOSNE: '{"orderId": "XYZ123", "responseCode": "0017", "responseDesc": "Incomplete merchant information", "storeId": "xxxxx"}
The response code "0017" is not even mentioned in the documentation.
This is my code
const otcTransaction = async () => {
try {
let url = `https://easypaystg.easypaisa.com.pk/easypay-service/rest/v4/initiate-ma-transaction`
let body = {
emailAddress: 'example#gmail.com',
mobileAccountNo: '03xxxxxxxxx',
orderId: 'XYZ123',
storeId: XXXXX,
transactionAmount: 10.0,
transactionType: 'MA',
}
const response = await axios.post(
url,
body,
{
headers: {
'Credentials': 'base64(username:password)'
},
})
console.log('RESPOSNE: ', response.data)
} catch (error) {
console.log(error.message)
}
}
Let me know if anyone has worked on EasyPaisa MA Transaction
Thanks in advance!
Ask for store Id from EasyPaisa,
I have checked its working fine with proper payload
I got in contact with the easypaisa team and i found out that the code i have written is fine. What needed to be done was that since i was in development and using development credentials i could only use the test phone number provided to me by easypaisa.
(PS keep in mind in test mode we can only make a transaction of Rs 10.0)
I’ve successfully setup the Customers payment methods and am able to retrieve them using the following code:
return stripe.paymentMethods
.list({ customer: customerId, type: 'card' })
.then((cards) => {
if (cards) {
return { cards: cards.data, error: null };
}
return {
error: 'Error creating client intent',
cards: null,
};
})
.catch((e) => {
console.log(e);
return { cards: null, error: 'Error fetching user cards' };
});
I’m now trying to create a direct PaymentIntent that will route the payment to a Stripe Connect connected account.
To do this I’m running this code:
if (cards && cards.cards && cards.cards.length > 0) {
const card = cards.cards[0];
const paymentIntent = await stripe.paymentIntents.create(
{
amount: amount,
customer: card.customer,
receipt_email: userEmail,
currency,
metadata: {
amount,
paymentMode: chargeType,
orderId,
},
description:
'My First Test Charge (created for API docs)',
application_fee_amount: 0,
},
{
stripeAccount: vendorStripeAccount,
}
);
const confirmedPaymentIntent = await stripe.paymentIntents.confirm(
paymentIntent.id,
{ payment_method: card.id }
);
This gives me the error ‘No such customer’, even though the customer ID is defined and I can find the customer in my Stripe dashboard. I also see the customer’s payment methods there.
What am I doing wrong?
The problem is that the Customer exists on your platform account, not the connected account you're trying to create the Payment Intent on.
In your first code snippet you don't specify a stripeAccount, so that API request is being made on your platform account. The Customer exists there, which is why that works as expected.
In your second code snippet you do specify a stripeAccount, which means that API request is being made on the connected account specified, not your platform account. You can read more about making API calls on connected accounts in Stripe's documentation.
To resolve the situation you either need to create the Payment Intent on your platform account as a destination charge, or create the Customer object on the connected account so it can be used there.
My website has products in several currencies up for sale on the same page, so a person can click the product that sold in EUR and pay in euros, or they can click the product that is sold in USD and pay in usd and so on...
The problem is that once you initialise the new PayPal SDK, you cannot change the currency that it accepts without:
destroying the element
changing the link to the SDK, so that it would accept a different currency
manually injecting it into the page
reinitialising it
As you can probably understand it is not very fast, stable or safe at the same time. Am I missing something? I know that you could send the currency as a parameter in the old Express Checkout version.
The PayPal documentation is infuriating, it is missing a lot of information and doesn't have a big community around it, so I could not find the answer to my question anywhere.
I have tried sending the currency in the payment parameters, but if it is different from the initialised currency, it throws a currency mismatch error once you try to confirm the payment.
Right now I am manually reinjecting and reinitialising the paypal SDK with the correct currency if the user clicks on the option of paying with PayPal, but it is slow and requires hardcoding sleep (although it is probably due to my lack of knowledge, there are probably better ways).
Here's the pseudocode of my current setup that is not acceptable:
initialisePaypalSDK(currency) {
destroy old initialisation
change link to paypal with new currency
inject new link to page
initialise the new sdk
sleep until the paypal variable is defined
showPayPalButton()
}
I expect that there is an easier and a safer way of changing the currency than this. Thanks.
You can use a backend to solve this issue.
First, define createOrder function like this:
const createOrder = async (data, actions) => {
return await axios.get('/yourbackend/api/get_order_id')
}
const onApprove = (data, actions) => {
// ... code to handle the payment status
}
paypal.Buttons({createOrder, onApprove}).render('#paypal-button-container')
Then just implement REST Api for order creation (/v2/checkout/orders) on your backend. Then return id of the created payment.
For those using React, this is now possible with the new library #paypal/react-paypal-js. From the README:
The usePayPalScriptReducer hook can be used to reload the JS SDK script when parameters like currency change. It provides the action resetOptions for reloading with new parameters. For example, here's how you can use it to change currency.
// get the state for the sdk script and the dispatch method
const [{ options }, dispatch] = usePayPalScriptReducer();
const [currency, setCurrency] = useState(options.currency);
function onCurrencyChange({ target: { value } }) {
setCurrency(value);
dispatch({
type: "resetOptions",
value: {
...scriptProviderOptions,
currency: value,
},
});
}
return (
<>
<select value={currency} onChange={onCurrencyChange}>
<option value="USD">United States dollar</option>
<option value="EUR">Euro</option>
</select>
<PayPalButtons />
</>
);
You can add the script once the currency has been selected.
let myScript = document.createElement("script");
myScript.setAttribute(
"src",
"https://www.paypal.com/sdk/js?client-id="your cliend id"&components=buttons¤cy=" + currencyVariable
);
let head = document.head;
head.insertBefore(myScript, head.firstElementChild);
myScript.addEventListener("load", scriptLoaded, false);
function scriptLoaded() {
console.log("Script is ready to rock and roll!");
paypal
.Buttons({
style: {
layout: "vertical",
color: "blue",
shape: "rect",
label: "paypal",
},
createOrder: function (data, actions) {
// Set up the transaction
return actions.order.create({
purchase_units: [
{
amount: {
value: traspasoCantidad,
},
payee: {
},
description: "",
},
],
application_context: {
},
});
},
onApprove: function (data, actions) {
return actions.order.capture().then(function (details) {
/* window.location.href = "approve.html"; */
});
},
onError: function (err) {
myApp.alert("Ha ocurrido un error al hacer el traspaso", "ERROR");
},
})
.render("#paypal-button-container");
}
I am using Laravel 5.1 trying to set it up with Stripe using Cashier.
I am using a custom button to execute the javascript (using Angular):
$scope.subscribe = function(plan){
var handler = StripeCheckout.configure({
key: 'pk_test_*************',
image: '/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
var data = 'stripeToken=' + token.id;
$http.post("/createSubscription", data).success(function(data, status) {
console.log(data);
});
}
});
handler.open({
name: 'basic',
description: 'basic monthly $100',
currency: "usd",
amount: 10000
});
$(window).on('popstate', function() {
handler.close();
});
};
And in my Laravel code I have:
public function createSubscription(Request $request)
{
$user = JWTAuth::parseToken()->authenticate();
$token = Input::get('stripeToken');
$user->subscription("basic_plan")->create($token);
return 'test';
}
But I keep getting an error saying "this customer has no attached payment source".
The returned token at this line:
token: function(token) {
...
Does contain the users email, card info (+ card token), and stripe token. But when I check my Stripe dashboard, a customer is added without any data (no card, no email and not set up with the subscription).
I am trying to create customers with a subscription plan via this form.
(I do have the Billable trait set up and included in the controller)
so I'm using Parse to handle a Stripe enabled app. We want our users to be able to cash out their in app credits, and we're planning on using Stripe to handle that. I've been able to create Customers in Stripe successfully, and link a bank account to these. Now I'm trying to initiate a transfer to one of these bank accounts, following
https://stripe.com/docs/tutorials/sending-transfers
But I'm running into an issue where Stripe.recipients is undefined.
Relevant code:
Initialization of Stripe:
var Stripe = require('stripe');
Stripe.initialize('sk_test_ukk7e8B46I39nxoUd6XILpPZ');
Parse Cloud Function for transferring:
Parse.Cloud.define("startTransfer", function(request, response) {
var userObjectId = request.params.userObjectId;
var credits = request.params.credits;
var StripeCustomer = Parse.Object.extend("StripeCustomer");
var stripeCustomerQuery = new Parse.Query(StripeCustomer);
stripeCustomerQuery.equalTo("userObj", userObjectId);
stripeCustomerQuery.find({
success: function(results) {
if(results.length == 0) {
} else if(results.length == 1) {
var customer = results[0];
// handle returning customer adding a new card
Stripe.Recipients.create({
name: customer.description,
type: "individual",
bank_account: customer.source,
email: customer.email
}, function(err, recipient) {
// recipient;
console.log("have a recipient");
if(err == nil) {
Stripe.transfers.create({
amount: credits,
currency: "usd",
recipient: recipient,
bank_account: customer.source,
statement_descriptor: "Cash Out"
}, function(err1, transfer) {
// asynchronously called
if(err == nil) {
response.success("Successfully transferred funds");
} else {
response.error(err1);
}
});
} else {
response.error(err);
}
});
}
}, error: function(error) {
reponse.error(error);
}
});
});
I'm calling this from iOS, using the PFCloud.callFunction API call. It seems to be hitting this code properly, but Recipients is said to be undefined in the error message, but the Stripe documentation requires it. How can I solve this?
Turns out, the Stripe cloud code module is indeed using an older version of Stripe. Therefore, according to this bug report, the solution is to download the newer SDK and manually add it to cloud code modules.
Source:
https://developers.facebook.com/bugs/523104684492016/
Actual post from the bug report (from Facebook employee):
Parse modules are using an old version of the API and there is no plan to update it in the near future.
As a workaround please download the newer SDKs directly off the third party site, place it in "cloud/" folder and import it using require();
We're going to close this by design.