Stripe invoice for one time charge - node.js

I'm trying to create a one-time charge in Stripe, I have already added all my products to Stripe, and I'm creating an order and charge like this:
const order = await stripe.orders.create({
customer: customer.id,
currency: 'usd',
items: [
'sku_0001',
'sku_0002',
],
email: 'test#test.com',
});
const charge = await stripe.orders.pay(order.id, {
customer: customer.id,
email: 'test#test.com',
});
However, on the invoice send my Stripe, it only shows one item, with description: Payment for order or_1GTmxxxxxxQjbLdncktm0.
How can I have all the ordered items show up on the invoice, or at the very least, something a bit more descriptive. My customers have no idea what this order ID means, or what they have paid for.

If you're developing a new integration, I'd advise against using Orders, since it is deprecated.
The best solution depends on what you're trying to do, beyond the invoice mechanics. One great option is to use Checkout for one-time payments to charge your customers. It does not leverage the products directly, but you can use that same data on your server to populate the line items.
Your other option is to create the Invoice directly, by adding line items to your customer. When you do this, and choose to send an email invoice, your customer will see a hosted invoice page with all invoiced items included.

Related

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.

Make email in Stripe Checkout for already existing customer read-only

I'm creating a Stripe checkout session (server-side) for already existing customer. According to Stripe documentation, I should pass customer Id as a customer parameter. Stripe internally gets the customer object and fills his email addess in the checkout UI. It works, but the email field is editable and I don't want users to be able to change their billing email. Is it possible to make this field read-only? Here my code:
await stripe.checkout.sessions.create({
line_items: [{ price: stripePriceId, quantity: 1 }],
customer: stripeCustomerId, // here I fill the stripe customer ID of the user
mode: 'subscription',
payment_method_types: ['card'],
allow_promotion_codes: true,
success_url: `${process.env.FRONTEND_URL}/premium-payment-success`,
cancel_url: `${process.env.FRONTEND_URL}/premium-payment-failure`
});
I'd really like to prevent users changing their Stripe checkout email, because knowing each user has the same billing email in Stripe would make things much easier.
Side note: When the user buys something for the first time, instead of customer parameter, I pass customer_email and the email is in this scenario read-only.
Any help is appreciated!
This is not currently possible, but I believe it's something Stripe is considering adding.

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.

New Customer created by Checkout, then create Subscription on Customer results in Error: This customer has no attached payment source

New Customer created by Checkout, then create a new Subscription on the same Customer by Node SDK results in Error: This customer has no attached payment source.
However if I look at the Customer at the dashboard, there is a Card, but not set as Default. Once it is "Set as Default" by clicking the ... it works.
Here is the code I used to create a new Subscription on a Customer:
const customer = 'cus_xxxxxx'
const plan = 'plan_xxxxxx'
stripe.subscriptions.create({
customer,
items: [
{
plan
}
]
})
I'm not sure if this is a limitation of Checkout since https://stripe.com/docs/payments/checkout says
Better support for saving customer details and reusing saved payment methods
Right now my workaround is to use webhook to update Customer's invoice_settings.default_payment_method on payment_method.attached.
This works but it feels strange. Did I miss something? Why does Checkout not set the only Card as invoice_settings.default_payment_method?
This behavior seems intentional on Stripe's part, the card from Checkout is attached to the Customer as a Payment Method, and is not set as default.
The same thing happens if you create a Customer directly with a PM,
let cust = await stripe.customers.create({ payment_method: "pm_card_visa" });
Also, fwiw, one can create their subscription directly from Checkout, passing a plan instead of sku https://stripe.com/docs/stripe-js/reference#stripe-redirect-to-checkout
From Stripe support:
Checkout does not currently support the ability to reuse saved payment
methods. We are aware that this is a feature request for a lot of our
users, and we are working on implementing this in the future.
If you'd like, you can see a roadmap of the updates we'll be making to
Checkout in the document below.
https://stripe.com/docs/payments/checkout#checkout-roadmap
That said, the work around you're doing for the moment is the same
work around that we're suggesting to users for the time being.
After a lot of digging I realized there is one step that is easy to miss in the docs: take the attached payment method and set it up as a default.
Here is my full server node.js code for creating a subscription:
const customerResponse = await stripe.customers.create({ email, name })
const customer = customerResponse.id
await stripe.paymentMethods.attach(paymentMethodId, { customer })
await stripe.customers.update(customer, {
invoice_settings: { default_payment_method: paymentMethodId }
})
await stripe.subscriptions.create({
customer,
items: [{ price: 'price_XXXXXX' }]
})
paymentMethodId name and email come from the client.

Must stripe destinations by account ids in order to make a charge

Is there anyway to make a customer be the recipient of a charge? From everything I see, it appears that the platform would have to create a stripe account for any individual that may receive charges on the platform. The following code works as long as the destination is a stripe account. Inside destination, I would like to be able to make the destination a customer instead of a stripe account, but I get errors when changing the destination[account] to destination[customer] as well as when I use a customer id in destination[account].
var arbitrary_charge = 100;
stripe.charges.create({
amount: arbitrary charge,
currency: "usd",
customer: stripe_customer_key,
destination: {
amount: .8*arbitrary_charge, //https://stripe.com/docs/connect/destination-charges
account: "acct_xxxxxxxxxxxx"
},
}).then(function(charge) {
console.log(charge)
})
There's no way to make a Customer the destination.
When developing a Platform there are two functions you're generally interested in, paying out and taking payments.
Stripe divides these functions up into separate object types: Accounts and Customers, respectively. You may have a case where you want to pay out AND take payments, in which case you'll usually want to create both a Customer and Account object for a given entity. Stripe also added a feature recently that allows you to debit from some Accounts.
to charge the customer and credit it to the connected account you have to do something like this
charge = Stripe::Charge.create({
amount: amount,
currency: "usd",
card: token.id,
description: "Charge for #{email}",
receipt_email: email,
}, {stripe_account: stripe_user_id})
stripe_user_id is the account id of the connected account of format "acct_xxxxxxxxxxxx"

Resources