Stripe adding paymentMethod to trial subscription and later validate credit card - node.js

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.

Related

NodeJs Update default credit card of customer for Stripe subscriptions and payment

I am building an app in which i am using stripe to handle all payments. And in our app we have a common feature where user can update the default card for their subscriptions but it not working as expected. I Have followed the instruction to update the customer payment method as described in the stripe documentation but it's not working as expected i still see the old credit card details as default payment method in stripe dashboard.
Updating the customer:
const customer = await stripe.customers.update(body.customerId, {
invoice_settings: {default_payment_method: body.pId},
});
Attaching payment method to customer and updating subscription:
const paymentMethod = await stripe.paymentMethods.attach(body.pId, {
customer: body.customerId,
});
await stripe.subscriptions.update(subscriptionDetails?.planId as string, {
default_payment_method: paymentMethod.id,
});
But still nothing, i am not sure what i am missing here but i couldn't update the default payment method.
The screenshot you shared refers to the payment methods saved on the Customer. If you wish to set the default payment method on the Customer, it will be under invoice_settings.default_payment_method on Customer API.
Subscription's default payment method is different from Customer's default payment method. With default_payment_method on Subscription API, it will only update the default on the Subscription object, not Customer object like the page you see. You should be able to find Subscription's default payment method at the Subscription page.
Subscription page link will be: https://dashboard.stripe.com/test/subscriptions/sub_xxx where sub_xxx is the Subscription ID.

Which payment method to use for Stripe Payment intent

I'm trying to auto charge customers on stripe in NodeJS
I have an issue where some customers have a:
default_source
and some have
invoice_settings.default_payment_method
My current workflow (C# WPF):
Create customer + Add subscription to customer
Get URL for portal
Customer adds card details on stripe portal
This works fine and payment are running well.
I also charge for SMS fees using a nodejs api:
async function chargeSMS(stripeCusID,chargeValue,chemistName,chemistID,countSMS){
//console.log(stripeCusID);
//console.log(chargeValue);
let customerObject;
let payMethodID;
customerObject = await stripe.customers.retrieve(
);
console.log("PaymentID received:" + customerObject.invoice_settings.default_payment_method);
payMethodID = customerObject.invoice_settings.default_payment_method;
await stripe.paymentIntents.create({
amount: chargeValue,
currency: 'aud',
customer: stripeCusID,
description: 'SMS Charges: ' + countSMS + " sent",
payment_method: payMethodID,
confirm: true
},
function(err, response) {
if (err) {
console.log("Charge", err.message,stripeCusID,chargeValue,chemistName);
return;
}
console.log("Successful SMS Charge:", response.id,chemistName);
chemCharged(chemistID);
})
}
This has also been working fine as a Cron on 1st of each month.
My issue is that recently one of my customer's cards expired.
They used my WPF to open the portal and add a new card
This worked.
HOWEVER this new card on the portal is only listed as
customer.default_source
Their
invoice_settings.default_payment_method
Is now null!
So my code above fails.
I've checked and:
All new customers using portal have their cards saved as invoice_settings.default_payment_method
any time a customer adds a new card it is only added as defult_source
I ahve no idea why this is the situation but I'm using the stripe customer portal so i would have thought they would add in the same way!
Any ideas how I can fix this or figure out what I've done wrong?
On the stripe web portal (my business) I can see that this customer DOES have a default card, and it looks the same as any other customer, but the api side has it registered under the different section!
You can add the Card as the Customer's invoice_settings.default_payment_method yourself by calling the Update Customer API.
FYI in a subscription the precedence chain is:
Subscription's default_payment_method
Subscription's default_source
Customer's invoice_settings.default_payment_method
Customer's default_source

How can I know if a Stripe trial subscription has ended without a webhook?

I am creating a Stripe customer and a subscription with a 7 day trial:
const stripeCustomer = await stripe.customers.create({
email: req.body.email
});
await stripe.subscriptions.create({
customer: stripeCustomer.id,
items: [{
price: process.env['STRIPE_PRICE_ID']
}],
trial_period_days: 7
})
When I check the status, it shows as trialing. After the trial ends, if I retrieve the subscription, it give a status of active. But that's not accurate because the customer didn't pay for the subscription yet.
What I want is a status that tells me that the trial has ended but that the customer has not paid yet so that I can direct the customer to the Stripe Portal when they sign in. I know there's a webhook that I can listen to, but I'd rather not worry about it at the exact moment that the trial ends. Instead, I want to deal with it when the customer signs in next.
You'd want to start your subscription with a payment_behavior of 'default_incomplete': https://stripe.com/docs/api/subscriptions/create#create_subscription-payment_behavior
That way the subscription's status will be incomplete after the trial ends, only transitioning to active once the first invoice has been paid.

How to prevent creating duplicate subscription in stripe when trial period is set on subscription

I am encoutering a problem with stripe. let me explain my working
scenario.my requirement is do not charge user for 14 days with card up front
1)user enter card details
2)sca popup appear
3)regardless of user complete the authentication or not a subscription is created in stripe because i set trial_end_date=>now()+14 days
4)user payment fails in some reason and attempt again, another subscription created
i am worried about the duplicate subscription as the stripe will attempt to pay after the 14 days for both of these subscription as it send a Stripe-hosted link for cardholders for both of these subscription
let me give a snapshot of what i have so far
$data['customer']='customerId';
$data['items']=[];
$data['items'][0]['plan']='stripe_plan_id'
$data['default_payment_method']='pm_xxxx'
$data['trial_end']= strtotime('+14 days');
$data['prorate']=true;
$data['tax_percent']=env('VAT_PERCENTAGE');
$data['expand']= ['latest_invoice.payment_intent', 'pending_setup_intent'];
try {
$subscription=\Stripe\Subscription::create($data);
}
catch(Exception $e) {
return response()->json(['success' => false,'message'=>$e->getMessage()]);
}
what i am missing? how to prevent the duplicate subscription scenario.please expain with the correct example which is i am missing.thanks in advance
I think the problem is in your payment flow, there is not a stripe api that explicitly detects duplicate subscription. You are after all allowed to assign more then 1 subscription per customer id. You can create idempotent keys, but that isn't for the same thing you're talking about, idempotent keys are for accidently hitting the submit button twice within the same timeframe.
The solution would be to attach a payment method to your stripe customer id before your subscription trial is over. For example if you are using stripe elements you would call
Node/JS Example below :
const result = await stripe.createPaymentMethod({
type: 'card',
card: card
})
then pass that result to your backend
const result = await stripe.paymentMethods.attach(paymentMethodId, {customerId})
You do not need to create a new subscription, as one has already been created for that user. Credit cards are assigned to customer Ids, and not to subscriptions. Stripe will do the rest.
You do also need to update the customer with the default payment method as follows :
const customer_update = await stripe.customers.update(stripeCustomerId,{invoice_settings: {default_payment_method:paymentMethodId}});
Now when you visit your dashboard you will see a default card assigned to your customer. Once the subscriptions falls out of the trail period, the default card will be charged.
So in this case there wont be a duplicate subscription created, as you are not calling stripe.subscriptions.create again.

How to set commission fee on stripe while Creating Separate Charges and Transfers?

How to set commission for Buyer & Seller both using stripe connect. I am using https://stripe.com/docs/connect/charges-transfers.
we want to hold money on our stripe account until job completed by seller. The amount is submitted by client(buyer) to out stripe platform .then, on job completing, it would be transferred to seller stripe account. (how to set commission for both while creating charge by the client(buyer) to our stripe platform account )?
input : Only pass application_fee without accountId
let chargeEntity = await stripe.charges.create({
amount,
//description: "Sample Charge",
source: sourceTokenId,
currency: currency,
customer: customerId,
application_fee_amount:application_fee,
//on_behalf_of:accountId
});
output :
"message": "Can only apply an application_fee when the request is made on behalf of another account (using an OAuth key, the Stripe-Account header, or the destination parameter)."
If you're using separate charges and transfers, there's no ability to pass an application fee.
Instead, simply withhold the funds you'd like to keep on your platform when you create the transfer, calling stripe.transfers.create. For example, if you created a charge for $100, only transfer $90, your platform retains $10 (minus any Stripe fees on the original $100 charge).
If you would rather use application_fee_amount, look at the destination payment flow; you could create the charge with destination but pass capture: false and then capture funds once work is completed.
https://stripe.com/docs/connect/destination-charges#application-fee

Resources