Have one stripe connect checkout session with multiple products trigger correct payouts to multiple different connected accounts - stripe-payments

I am building a marketplace for people to sell digital products with nextjs, firebase and firebase cloud functions. I am able to credit one account with a cart of one or multiple products by following the documentation here https://stripe.com/docs/connect/collect-then-transfer-guide. But I would say it would be important to be able to put items from different authors into your cart.
This is my code that works well for one or multiple products and one connected account.
export const checkoutSessionSingular = functions.https.onCall(async (data, context) => {
const session:any = await stripe.checkout.sessions.create({
line_items: data.line_items,
mode: "payment",
success_url: "***",
cancel_url: "***",
payment_intent_data: {
application_fee_amount: data.fee_amount,
transfer_data: {
destination: data.connectId,
},
},
});
return session;
});
I have tried putting payment data, transfer data or destination into an array, but that always breaks it.
I tried using transfers and transfer groups, but I seem to lose all the valuable data in the stripe dashboard about which product the money comes from and I can't manage to make it work properly with the very limited documentation.
I also tried using destination charges but couldn't make it work.
If something like transfer groups are the solution, I would welcome a link to a proper example implementation or something more helpful.
What should I do to just have a normal working cart for a multi vendor marketplace? I already looked at every page of their documentation 30 times. Thanks.

If you want to send the money to multiple connected accounts, then you have to use Separate Charges & Transfers. So in your case you need to:
Create the Checkout Session and collect the payment, without any application_fee_amount or transfer_data
Then manually create Transfers between your main Stripe account and the connected accounts, with this endpoint

Related

Generate Stripe Subscription Link

I want to create a payment link for a subscription in the backend and send it to the client without having any frontend site.
const customer = await stripe.customers.create({
metadata: {
author_id: "author_id",
custom_id: "custom_id",
},
....
}
First I created a customer, using my app specific credentials. Then I want to generate a link using this custome id, but I'm kinda confused how to make it work,
Stripe documentation shows something like this,
await stripe.paymentLinks.create({
line_items: [{price: price_id, quantity: 1}],
});
But it creates a completely new product price.
Is there any way to create a link using pre made product price id and customer metadata using Stripe NodeJS backend?
You cannot pass a pre-existing Customer object (cus_xxx) when creating a Payment Link. The default behaviour for Payment Links infer that a new Customer object be created depending on other parameters set on the Payment Link, as noted in the documentation:
The Checkout Session will only create a Customer if it is required for Session confirmation. Currently, only subscription mode Sessions require a Customer.

Angular/node.js Stripe Checkout Integration (1 account to facilitate payments from third party payer to third party receiver)

Man, I have been at this for some days and can't find a good solution to this. I want to use my account (via public key and private key) to facilitate payments from one account to another (nothing will be going into my account). On the front-end I have:
checkout(amount) {
const strikeCheckout = (<any>window).StripeCheckout.configure({
key: environment.PRODUCTION==='true'?stripeLiveClientId:stripeTestClientId,
locale: 'auto',
token: (stripeToken: any) => {
if(stripeToken){
console.log(stripeToken)
this.createCharge(stripeToken,amount)
}
}
});
strikeCheckout.open({
name: 'Camel Stripe',
description: 'Stripe Checkout',
amount: amount
});
}
Just a small snipet, but essentially this just captures the credit card and email and ensures it is a valid credit card and then makes a stripe token. I then pass this token to the node backend and do:
stripe.paymentIntents.create({
amount: priceInPence,
currency: 'usd',
source: stripeTokenId,
capture: false, // note that capture: false
}).then(charge => {
return res.json({ success: true, message: 'Success', result: charge })
}).catch(error => {
res.status(400).json({ success: false, status: 400, message: error });
});
//})
};
No matter how I structure it, it always end's up getting the payment to my account, the account with the public/private key. Does anyone know a way I can use this token since it has the necessary information, and send the money to another account?
You can't accept payments and move the funds into a completely different Stripe account unless you're using Connect.
To piggy back on Paul's comment, after much research on Stripe Connect I wanted to share my findings. Please note this is specific to my use case and is using angular/express.
Connect offers multi-party payments, meaning you can receive funds from 1 user, then route them into another users account. You will need a stripe connect account. After that you connect an account, aka create account. They offer 3 account types all these account types need to be
Custom: basically is if you don't want the account you're routing to to see anything stripe related, meaning it is white labeled and the user has no dashboard or view of what is going on in the background.
Standard(the one I chose): this account will have a full stripe dashboard, it has all the functionality that an account would have that you make on your own. You will get a unique account id relevant to your specific connect account environment, on their end, they will have multiple account ids depending on how many other connects they are connected to, or if it is an already existing account. You will need to use this api to get the link to have them verify information before they are integrated into your connect environment account link api
Express: they will have a slimmed down version of a dashboard, it is similar to standard with less functionality
At this point you're ready to start routing payments. I did angular on the front-end, here is an example basically this simply creates a stripeToken, which is a verification that the card data is valid. You need to pass this to a backend to make use of it, this will not create any charges.
On the backend, I used express, you use the charge api You pass the stripeToken as the source attribute. One important step is to add the stripe account id you see in your connected accounts dashboard. It should look similar to:
stripe.charges.create({
amount: priceInPence,
currency: 'usd',
source: stripeTokenId,
capture: false, // note that capture: false
},{
stripeAccount:'{{acctId}}'
})
This should be sufficient to get your payments routing to the necessary account while leveraging a simple UI checkout.
One thing to note about the charges API, this is an older API and has less functionality. For my use case (US CA only with only card payments) it is sufficient. If you have a more complicated use case, or maybe your app is for heavy prod use to many users you should look into payment intents.

Send money to a bank account using Stripe | Node JS

So I have this React application where users can buy gift cards online, and I'm using Stripe Payments. So far, the users can pay the money, except it will go to me(through Stripe), not to the merchant selling the Gift Cards on my app.
Is there a way with Stripe to send money to a bank account? Keep in mind that the bank account will be different for each Gift Card any users can buy.
For example, one person selling the gift cards will be the one earning the money through a different bank account than another person.
If there is a way, please tell me how to implement it, and thank you very much in advance.
I finally figured how to do this. You have to follow these steps:
1: Integrate Stripe Checkout
2: Integrate Stripe Onboarding for express accounts
These two steps are the fundamental steps in doing this.
How To Integrate Stripe Checkout:
You can get stripe checkout by using the
stripe.checkout.sessions.create
method. You can then pass in arguments like:
payment_method_types: ["card"],
locale: locale,
line_items: [
{
name: `${Name}`,
images: ["Images"],
quantity: 1,
currency: usd,
amount: price, // Keep the
// amount on the server to prevent customers
// from manipulating on client
},
],
payment_intent_data: {
transfer_data: {
destination: product.id,
},
},
success_url: `success`,
cancel_url: `cancel`,
What this will do is create a new checkout session to use.
Next Step, Onboard the businesses
All you have to do for this is to go to a URL:
const url = `https://connect.stripe.com/express/oauth/authorize?${args.toString()}
where args is this:
const state = uuid();
const args = new URLSearchParams({
state,
client_id: process.env.STRIPE_CLIENT_ID,
});
Send this data to your frontend and you will get a good looking form that onboard users and creates express accounts for them.
The basic concept is simple, you onboard the businesses, which creates a stripe account for them. Then with the checkout form, you send the money to that created stripe account. This account will automatically deliver to the businesses bank or debit account, thus making customer to merchant payments.
Here are some helpful documentation I used to solve the problem:
https://stripe.com/docs/payments/checkout
https://stripe.com/docs/payments/checkout/accept-a-payment
https://stripe.com/docs/connect
https://stripe.com/docs/connect/collect-then-transfer-guide
https://stripe.com/docs/connect/express-accounts
I hope this helps!

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.

Stripe connect share card source not working

I am saving customers and their sources on my platform, and trying to create charges for my connected accounts. I am able to successfully create destination charges, but I'm having trouble with creating direct charges.
I've tried creating a token per: https://stripe.com/docs/connect/shared-customers
If I create a token using just the customer the example, the error is:
'You provided a customer without specifying a source. The default source of the customer is a source and cannot be shared from existing customers.'
Even though the documentation says that you need "The card or bank account ID for that customer, if you want to charge a specific card or bank account rather than the default".
I cannot find a parameter that lets me specify a source as well or instead of a customer.
I've tried sharing the customer's chosen source with the connected account per: https://stripe.com/docs/sources/connect#shared-card-sources
which results in the error:
'Sending credit card numbers directly to the Stripe API is generally unsafe. We suggest you use test tokens that map to the test card you are using, see https://stripe.com/docs/testing.'
I tried attaching a test token (tok_visa) to my customer, and creating a charge with that, but that had the same result.
Every time I have some success I end up with the error about sending numbers being unsafe even though I'm only ever sending Stripe's provided token or source ID's.
I've tried this:
const newToken = await stripe.tokens.create({
customer: customerId,
}, {
stripe_account: stripeAccountId,
}).catch((e) => {
console.log(e);
});
and this:
const newToken = await stripe.sources.create({
customer: customerId,
usage: 'single_use',
original_source: sourceId,
}, {
stripe_account: stripeAccountId,
}).catch((e) => {
console.log(e);
});
The only success I've had is creating the direct charge with a test token (tok_visa), completely bypassing the sharing of tokens/sources. No other combination seems to work. But that leaves me at a loss as to how to get a real shared token when I need it.
I found out I should be using sources, not tokens. And it turns out I was accidentally using the whole newToken as the source for the charge. It's working now that I'm passing the newToken.id to the charge.

Resources