Stripe Offline Payments - node.js

I am trying to do offline payments using stripe, for which I need to authorize SetupIntent for future payments.
I am creating SetupIntent in Node js as below -
const setupIntent = await stripe.setupIntents.create({
customer: customer.id,
payment_method_types: ['card'],
usage: 'off_session',
});
And I am confirming SetupIntent in React as below -
stripe.confirmCardSetup(setupResponse.clientSecret, {
payment_method: {
card: elements.getElement(CardElement),
billing_details: {
name: name,
email: email
},
}
})
.then(async function (result) {
});
As mentioned in stripe documentation, to do offline payments we need to create mandate_data object. But for it payment method is required and confirm should be true.
Since I am attaching payment method to SetupIntent from React frontend, after SetupIntent is created, so, I am unable to use mandate_data.
I have also followed https://stripe.com/docs/payments/save-and-reuse this documentation. But it gives me authentication required error every time for offline payments.
Any pointers please.

In general, cards set up for future offline usage are subject to re-authentication at the discretion of the bank/issuer.
If you're using Indian-issued cards in particular, then it is currently expected that every payment will require authentication. See docs here:
https://support.stripe.com/questions/rbi-regulations-guide-for-direct-payments-users

Related

How to retrieve receipt_url upon successful payment completion in Stripe

We are using the Stripe API to make payments for invoices using a SAPUI5/Fiori UI. The payment intent create happens via a node.js project. We are successfully able to initiate the payment and from the Stripe dashboard Payments section we can see that the payment gets processed successfully.
We have the requirement, that upon successful payment completion, we need to redirect the user to the receipt URL (receipt_url) to display the payment receipt of the just processed invoice. Below is the code we are using to invoke the create payment intent on the Stripe server:
const paymentIntent = await stripe.paymentIntents.create(
{
payment_method_types: ['card', 'us_bank_account'],
metadata: {
....
....
....
},
},
{apiKey: secretKey}
);
res.send({
clientSecret: paymentIntent.client_secret,
});
According to the Stripe documentation, we can retrieve the receipt URL by retrieving the charge within the paymentIntent, but the response we receive upon successful processing of the payment by Stripe does not contain the charge object, it just has the payment id. Is it possible in any way, to retrieve the receipt URL using only the payment intent id?
Calling the payment intent create on Stripe to process the payment, but we are not getting in the response the receipt_url value where we want to redirect the user to, upon successful payment completion.
You can find the receipt_url property on the latest_charge property (make sure you use an API version greater than 2022-11-15; in older versions, it was the last item of charges property), which you can expand on your successful Payment Intent.
For that, you need to add a parameter expand when you create a Payment Intent:
const paymentIntent = await stripe.paymentIntents.create({
…
expand: [“latest_charge”]
});
const receiptUrl = paymentIntent.latest_charge.receipt_url;

Issues cloning a Stripe platform customer to a Connected Account Customer - No such payment_intent: 'pi_abc...zyx'

I am using the React components for Stripe.js to try and process a payment for a connected account, and collect a fee off of each payment. I am not sure if the flow between my client and server is properly picking up my cloned customer and payment method. When my test customer tries to pay, I get "No such payment_intent: 'pi_abc...zyx'". I have ensured I am using the correct private test keys on both client and server. My Connected accounts are express accounts. When I go to my Stripe dashboard to look at the 'Customers' tab under 'Connect', this is what I see:
It looks like a blank entry is being created each time I make a payment attempt.
Here are the steps I am currently taking to let the platform customer pay a Connected account:
When a customer first signs up on my website, the Stripe-firebase extension I have installed automatically generates a customer ID. These are now considered my platform customers
I allow a platform customer to create an Express Connected account, this works perfectly fine. I now have their Stripe Account Id ex: 'acct_abc...xyz`.
Now here is the flow for when a platform customer tries to make a payment to a Connected Account:
React/Client Side - loadStripe with only the test key, not with a Stripe Connected account Id
const stripePromise = loadStripe('pk_test_abc...');. I provide this to <Elements stripe={stripePromise}>
React/Client Side - User fills in payment form and presses submit. Create a paymentMethodReq from client/platform:
const paymentMethodReq = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: billingDetails
});
Node/Server Side - Client then makes a request to my server to try and clone the platform payment method to a Connected account:
const serverPaymentMethod = await stripe.paymentMethods.create({
customer: data.customerStripeId, // Customer ID of the customer paying (platform customer)
payment_method: data.paymentMethodId, // Using the payment method Id generated from 'paymentMethodReq' on the client side
}, {
stripeAccount: connectedAccountStripeAccountId, // Using the Connected Account
});
Node/Server Side - Client then makes a request to my server to create/"clone" a new customer from the platform and link it to the Connected account
const customer = await stripe.customers.create({
payment_method: data.paymentMethodId, //Payment method id generated from 'serverPaymentMethod' above
}, {
stripeAccount: connectedAccountStripeAccountId, // Using the same Connected Account
});
Node/Server Side - Client then makes a request to my server to create a payment intent with the customer id that was linked to the Connected account along with the payment method that was generated from the server
const intent = await stripe.paymentIntents.create({
amount: data.price * 100,
currency: 'usd',
payment_method_types: ['card'],
payment_method: data.paymentMethodId, // Payment method id generated from 'serverPaymentMethod' above
customer: data.customerStripeId, // Customer Id generated from 'customer' above
description: data.desc,
capture_method: 'manual',
application_fee_amount: (data.price * 100) * 0.15,
}
React/Client Side - I try to confirm the card payment which results in the "No such payment_intent: 'pi_abc...zyx'" error
const confirmedCardPayment = await stripe.confirmCardPayment(paymentIntentResult?.data?.client_secret, {
payment_method: serverPaymentMethod?.data.id //Payment method id generated from 'serverPaymentMethod' above
});
I tried replacing stripe.confirmCardPayment on the client with a call to my server that instead confirms the payment intent like so:
const confirmPaymentIntent = await stripe.paymentIntents.confirm(
data.paymentIntentId, // Payment intent id generated from 'intent' above
{
payment_method: data.paymentMethodId // Payment method id generated from 'serverPaymentMethod' above
});
and this also results in "No such payment_intent 'pi_3K...9Rx'"
If anyone could help me figure out where I am going wrong in this process, that would be greatly appreciated. Thank you
The error indicates that the PaymentIntent belongs to a different account with whose your current call is using a key of. It could be:
You created the PaymentIntent on Platform account, then confirm it
from your Connected Account
You created the PaymentIntent on Connected Account, then confirm it
from your Platform Account
While I am seeing both PaymentIntent creation and confirmation calls doesn't use the stripeAccount parameter, I suspect that you missed the code somewhere and the PaymentIntent was actually created in your Connected Account, lead to #2 possibility above.
To debug this you can check which account the PaymentIntent belongs to, by searching its ID on Dashboard's search box, or simply write to Stripe Support with the ID and they can check it for you.

Stripe: Make transfers from a user's card and not from my account balance

I have already followed Stripe's documentation to make transfers. I get an error telling me that I do not have sufficient funds on my balance. In my case, I would like not to transfer the money from my account but from the card of the user making the purchase. I specify that I need to make transfers because I can have several accounts connected for a single payment.
Here is the steps I follow:
On the client side (Flutter), I ask a user to enter his bank card information. I then generate a PaymentMethod object that I send to my server (Node.js).
(server side), I execute the paymentIntent.create method
const paymentIntent = await stripe.paymentIntents.create({
amount: amount,
currency: "eur",
payment_method: paym,// id get from client side
payment_method_types: ["card"],
transfer_group: "{ORDER1}",
});
(server side), create transfers
const transfer1 = await stripe.transfers.create({
amount: amount / 2,
currency: "eur",
destination: "acct_###########",
transfer_group: "{ORDER1}",
source_transaction: ?,
});
I know that I have to fill in the source_transaction field to make the link between PaymentIntent and Transfer. I can retrieve this information in the PaymentIntent object with the charge field but it is empty. This means that I must first validate the payment on the client side before making the transfer.
Only when I validate it on the customer side, I receive the following error No such payment_intent when I execute:
StripePayment.confirmPaymentIntent(PaymentIntent(
paymentMethodId: result.data['paymentIntent']['payment_method'],
clientSecret: result.data['paymentIntent']['client_secret']))
Is there something I do wrong or missing ? Do you have an example of a simple implementation ?
Thank you for your time.
You should be able to use the Payment Intent ID as the source_transaction value.

Stripe adding paymentMethod to trial subscription and later validate credit card

I'm working on stripe integration with react node.js
While creating a subscription without trial, I have no issues, and all use-cases are much simple.
But, I'm trying to create free trial without collecting credit card details, later when trial expired, I would like to collect credit card details
Server side: Creating Trial Subscription without payment method:
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{ price: priceId }],
trial_end: expiredAt.unix(),
expand: ['latest_invoice.payment_intent'],
});
ClientSide: Later when trial expired, I would like to collect credit card details(paymentMethod), check if user action is required due to failures or 3ds and update the subscription by updating the customer's default payment_method:
const updateCustomerDefaultPaymentMethod = await stripe.customers.update(
customerId,
{
invoice_settings: {
default_payment_method: req.body.paymentMethodId,
},
}
);
How can I update the subscription to perform paymentIntent or charge the user, and return to client same subscription object with status 'in_complete' same as when creating subscription without trial_period?
Currently when running my code, I keep getting status='active' because the first invoice is in status='paid' with price of '0$'.
In the case of a free trial, creating a subscription won't result in an initial payment, and Stripe will instead create a SetupIntent under the hood for you automatically. This SetupIntent is meant to be used when collecting the customer's payment method. So at any point during the trial, the customer would need to return to your app to enter their credit card details, which you would then save using the SetupIntent:
subscription.pending_setup_intent
Confirm the SetupIntent with the collected card details
Once the payment method is setup and saved to the customer (as the default payment method for invoices) it will be used to pay for the subscription's first invoice when the trial ends. The first payment after a trial is considered an off-session payment (last FAQ), so if that payment fails Stripe will attempt to recollect the payment using the usual smart retries and dunning functionality.
In a nutshell, you need to use the SetupIntent that's created (and attached to the subscription) to save the user's payment information.

Stripe TypeError: Cannot read property 'payment_intent' of undefined

I'm integrating the payment methods to the app with Stripe and Paypal and now working on Stripe integration.
The backend is Node, Sails.js, and the frontend is React.js.
I followed the guide they provided but and tested the payment processing using testing card.
But I got the error, which says TypeError: Cannot read property 'payment_intent' of undefined.
Here is my code.
- Frontend
this.props.stripe.createPaymentMethod({
type: 'card',
card: cardElement,
}).then(({paymentMethod}) => {
// API call
})
- Backend
subscribe = await stripe.subscriptions.create({
customer: customerId,
items: [
{price: plan.stripe.stripeId},
],
expand: ['latest_invoice.payment_intent']
});
Please help me to fix this issue.
In my opinion you don't have to create the PaymentIntent per subscrition.
Here is what Stripe API docs says about paymentIntent.
A PaymentIntent guides you through the process of collecting a payment from your customer. We recommend that you create exactly one PaymentIntent for each order or customer session in your system. You can reference the PaymentIntent later to see the history of payment attempts for a particular session.
So they recommend to create the paymentIntent per transaction and in subscription case, the payment is proceed in background automatically and paymentIntent is also generated in my experience.
But on the other hand in checkout option, you need to create the paymentIntent first before proceeding the payment.
I think you code was not wrong but I think you didn't follow the correct guide from Stripe or used wrong credit card.
Please refer this link:
Stripe API Payment_intents

Resources