Stripe Node - Calculating application fee AFTER discount coupon is used in checkout - node.js

I have a Stripe Checkout Session linked to a connected account. The connected account is subject to a 10% charge from my platform. It works well currently, however now I have added the ability for customers to use coupons in the checkout window, the application fee is being calculated from the total amount before the discount is applied.
For example, if I charge €32, the application fee is €3.20. If a discount reduces the charge to €10, the fee should be €1. But it is still charging €3.20.
I have a function which calculates the application fee amount, the problem is that this is done when the checkout session is created - this happens before the customer enters the discount.
I can't think of a way around this issue since the session is always created prior to the discount being applied. Any help/suggestions are appreciated!!
const calculateApplicationFeeAmount = (total) => total * site.stripeFee;
const session = await stripe.checkout.sessions.create(
{
payment_method_types: ["card"],
line_items: [
{
name: price.name,
amount: price.amount,
currency: site.currency,
quantity: 1,
},
],
payment_intent_data: {
application_fee_amount: calculateApplicationFeeAmount(price.amount),
description: price.name,
},
mode: "payment",
allow_promotion_codes: true,
success_url: `${config.baseUrl.url}/unlock/session/{CHECKOUT_SESSION_ID}`,
cancel_url: `${config.baseUrl.url}/unlock/${deviceID}`,
metadata: {
deviceID: deviceID,
},
},
{
stripeAccount: site.stripeAccount,
}
);
return session;

The best solution here would probably be to :
Use payment_intent_data.capture_method:manual when creating the checkout session
After receiving the checkout.session.completed event, update the application_fee_amount on the PaymentIntent
Capture the PaymentIntent
The limitation is that not all payment methods support manual capture.
Alternatively, you could also refund the application fee later : https://stripe.com/docs/api/fee_refunds/create

Related

How can I create a Stripe checkout with custom amount to be paid?

When creating a checkout session, I am providing line items with price_data and quantity and in the checkout I see the correct amount. For some payments the customer can use their in-app points which will reduce some amount from the total checkout amount. How can I apply that to the checkout?
Example:
You buy 3 T-shirts (3x20) and one cap (1x15) which means you need to pay 75.00 (of some unit)
You use the in-app option to use your points which gives you 5.00, so now your checkout session must be a custom value (70.00).
I am using this API:
https://stripe.com/docs/api/checkout/sessions/create
The only solution that I came up with was to create a coupon right before creating the checkout and apply it to the checkout, but I don't know if that's safe.
Yes coupon should works with Checkout Session.
Maybe this will work.
var stripe = require("stripe")("YOUR_STRIPE_SECRET");
stripe.checkout.sessions.create(
{
payment_method_types: ["card"],
line_items: [
{
price: "YOUR_PRICE_ID",
quantity: 1,
},
],
success_url: "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://example.com/cancel",
},
function(err, session) {
console.log(session.id);
}
);

Stripe Checkout session with total price and not unit_price

I'm working on a project currently. and I'm making use of stripe, the stripe.checkout.session.create function works perfectly.
const session = await stripe.checkout.sessions.create({
line_items: [
{
price_data: {
currency: "usd",
unit_amount: 500,
product_data: {
name: "name of the product",
},
},
quantity: 1,
},
],
mode: "payment",
success_url: "http://example.com/success",
cancel_url: "http://example.com/",
});
but the only issue i have is it receives only unit price.
but i want a field where i can pass only total Price, cause in my code , if the users applys a discount to a product , it deducts it from the product total price meanwhile the unit price for each product is stable.
My question is basically is there a field where i can pass total price.
Short answer is that you can't. You need to use the line_items parameter and either pass a Price object ID (price_xxx) or use ad-hoc pricing with the price_data parameter. Checkout will then compute the total from all line items, factoring in any discounts that you provide.
You have a couple of options to achieve the behaviour you want:
Re-calculate the price_data.unit_amount value to reflect the discount applied by your customers.
Utilise Stripe coupons to apply to the Checkout Session which will take care of the dedication for you.

Stripe Node.js - How to split a payment between several beneficiaries (connected accounts)?

For my first implementation, I transfer the amount of the transaction directly to a beneficiary from a paymentMethod Id retrieved from my app (Flutter). Now my goal would be to split the payment between several beneficiaries on the same transaction.
First implementation code:
var clonedPaymentMethod = await stripe.paymentMethods.create(
{
payment_method: paym,
},
{
stripeAccount: stripeVendorAccount,
}
);
var paymentIntent = await stripe.paymentIntents.create(
{
amount: amount,
currency: currency,
payment_method: clonedPaymentMethod.id,
confirmation_method: "automatic",
confirm: true,
application_fee_amount: fee,
description: "desc",
},
{
stripeAccount: stripeVendorAccount,
}
);
const paymentIntentReference = paymentIntent;
By checking the documentation, I noticed that the stripe.paymentMethods.create method was no longer specified, and that the stripe.transfers.create methods were added.
This code is attempting to clone a payment method to a connected account and then create a direct charge on that account. In order to create charges and then to split the funds of that charge to separate connected accounts a different approach would be needed. The model would be closer to "Separate charges and transfers", where the charge is made on that platform and then some amounts are shared among the connected accounts using transfers. A full description is outlined here [1].
[1] https://stripe.com/docs/connect/charges-transfers

Stripe default card in checkout

Is there a way to fill fields in a Stripe checkout page when customer comes back? I've tried to set default payment method for customer with webhooks (payment_method.attached) but this default credit card won't show up during checkout. Instead Stripe creates new payment method for the customer every time he pays. It's strange to have dozen of exactly the same credit cards in a Stripe dashboard. Here is my current code:
const checkout = await stripe.checkout.sessions.create({
cancel_url,
success_url,
payment_method_types: ["card"],
mode: "payment",
customer: stripeCustomer,
client_reference_id: stripeCustomer,
metadata: {
//...
},
line_items: [{
price_data: {
currency: 'usd',
product_data: {
name: packetDisplayName,
},
unit_amount: packetPrice,
},
quantity: 1
}]
})
I later use session id to redirect to checkout then perform few operations in a webhook endpoint
Thanks for taking the time to read my question, cheers
Checkout does not currently support using Payment Methods already attached to the provided Customer.
More broadly, there is not a concept "default" payment method for one-time payments for a customer, only for invoices.
If you already have a known Customer and an attached payment method, you also have the option of creating the payment yourself, directly, using those details.
try its work for me in Node.JS
For add card in node js
let card = await stripe.customers.createSource(customerid, {
source: token
});
Make card as default card
let updatecard = await stripe.customers.update(customerid, {
default_source: card.id
});
you can replace card.id if you just want update card only

Stripe Checkout server-side load Customer cards

In Stripe Checkout, using the server integration, is it possible to preload the customer saved cards?
I have a customer with a previous purchase history and I would like to let him pick a saved card details during checkout.
In the CRM I can see that cus_EyGeAZaPVHwUVg has the credit card stored (the test one for now, 4242...), but upon a new checkout I am not presented with that, even though the email is filled correctly.
I haven't seen any option in the docs, this is the code:
stripe.checkout.sessions.create({
payment_method_types: [paymentMethod],
line_items: [{
name: name,
description: description,
images: [imageUrl],
amount: amount,
currency: currency,
quantity: 1
}],
success_url: 'http://localhost:3000/success',
cancel_url: 'http://localhost:3000/cancel',
customer: 'cus_EyGeAZaPVHwUVg'
})

Resources