#L0rdandBooz
1 messages · Page 1 of 1 (latest)
hello! can you share more on what's your question?
Hey Alex!
I'm following this guide and having a heck of a time getting it to work.
I don't understand how the stripe account link modal just shows up and the steps to get there
I'm stuck on getting the modal to show up / using the collectBankAccount for setup. I'm fine in regards to creating setupIntent
Basically i'm stuck after getting the client secret
I'm using next.js if that helps
hmmm, i can see how that page can be confusing. We don't have a Next.js specific example, but you can take a look at https://stripe.com/docs/payments/ach-debit/set-up-payment for a general guide to how to use the collectBankAccount for setup
I looked through that and unfortunately it didn't really help 😦
It feels like there's so much code left out because where does the modal even appear from? It looks like it's provided by stripe but I never do anything to show it.
the modal is automatically displayed by Stripe
I wish there was a full file I could take a look at so I can see how everything interacts. Is that by chance a thing?
which is this one right?
to clarify - the example is for accepting payments, which isn't exactly the same as what you're looking to do i.e. saving the bank account details for setup. But you can still see how the modal is displayed
Right which helps.
stripe.collectBankAccountForSetup({
clientSecret: clientSecret,
params: {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: accountHolderNameField.value,
email: emailField.value,
},
},
},
expand: ['payment_method'],
})
is the expand on this what makes the modal pop out?
no, nothing in the parameters specifically is what makes the modal pop out. when stripe.collectBankAccountForSetup is called, stripe.js will automatically display the modal to collect the bank details
OK. How does it know which page and where on the page to display it?
Is this what does it?
it's a modal, so it'll pop up on the page where you're calling it. I'm a bit confused by the question where on the page to display it - do you have any concerns about this?
No what you said about it just popping up makes sense. How do I tell it what page to pop up on though?
Is there a component I need to place in the body or something specific I need to import?
you don't need to tell it what page to pop up on, it'll pop up on the page where that specific line of code is called
Ok I think that makes sense. I'm going to try and few things and see how it goesðŸ˜
Thank you so much
If you wouldn't mind leaving this ticket open until I report back so it's easily findable?
the thread will automatically close, but you can reach out again on the main channel if you need help again or have more questions
generally, i've found it a lot easier to understand once i've tried something out
Yeah that's the issue I've been trying for hours lol
This additional bit of insight is going to change that though
It will work!
Hey alex
I'm back
const response = await stripe.collectBankAccountForSetup(client_secret, {
billing_details: {
name: "John Doe",
email: "test@test.com",
},
});
TypeError: stripe.collectBankAccountForSetup is not a function
I'm getting a type error on this so I'm unable to call it
did you import stripe.js?
What's the proper way to do it? I've never seen an import statement like this. <script src="https://js.stripe.com/v3/"></script>
ReferenceError: Cannot access 'loadStripe' before initialization
import {loadStripe} from '@stripe/stripe-js';
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const loadStripe = await loadStripe(process.env.STRIPE_SECRET_KEY);
If you're using React, you should be able to import Stripe with:
import { loadStripe } from '@stripe/stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_CLIENT_KEY);
// Then pass stripePromise into Elements creation
<Elements stripe={stripePromise}>
the key should be publishable key, not secret key
Thank you! I'm getting this error now TypeError: Cannot read properties of null (reading 'collectBankAccountForSetup')
How do you initialise stripe in stripe.collectBankAccountForSetup?
const response = await loadStripes.collectBankAccountForSetup({
clientSecret: client_secret,
params: {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'john doe',
email: 'bruh',
},
},
},
});
The stripe here should be from useStripe(), not from loadStripe. loadStripe is only for Elements initialisation:
import { useStripe } from '@stripe/react-stripe-js';
const stripe = useStripe();
const result = await stripe.collectBankAccountForSetup(...);
Do you by chance know next.js at all?
TypeError: Cannot read properties of null (reading 'useContext')
Still getting the same error
It's basically react but you have to handle await and stuff a little differently
const useStripes = useStripe(process.env.STRIPE_SECRET_KEY);
here's specifically what I'm doing for where the error currently is
I have this in my
export async function getServerSideProps(ctx) {
so it'll just render the modal on page load
You don't have to put secret key in useStripe
Just simply:
const stripe = useStripe();
I removed it and I'm still receiving the same error
Can you share the full code?
Like how you initialise the stripe and call collectBankAccountForSetup?
yeah standby
import {ErrorMessage, Field, Form, Formik} from "formik";
import Input from "./components/Input";
import {ClipboardListIcon} from "@heroicons/react/outline";
import React, {useState} from "react";
import {toast} from "react-hot-toast";
import axios from "axios";
import {getSession, signOut, useSession} from "next-auth/react";
import * as yup from "yup";
import {prisma} from "../lib/prisma";
import {useRouter} from "next/router";
import { useStripe } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import {Elements} from "@stripe/react-stripe-js";
my import statements
If you need more I have more in the file but this is just the data fetching section
It should be something like this in Next/React:
import { useStripe } from '@stripe/react-stripe-js';
type BankAccountProps = {
clientSecret: string,
}
const BankAccountForm = (props: BankAccountProps) => {
const handleConfirm = async () => {
const stripe = useStripe();
if (!stripe) {
console.log('No stripe');
}
const result = await stripe.collectBankAccountForSetup(props.clientSecret, {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'Jane Yong',
email: 'test@test.com',
},
},
});
};
};
so do I need to render that or will it be done automatically?
I tested in my own and it works fine.
Data collection should be done by your end and pass them into collectBankAccountForSetup
The parameters in your collectBankAccountForSetup is incorrect
Parameters in react's version is different
My parameters look the same as yours. Forgive me but what am I missing?
It looks like you wrapped it into a bankaccount form function and are passing the secret in there but otherwise it seems like I'm doing the same thing
Mine doesn't have params whereas yours has
oh not sure how i missed that
I recommend copying mine to yours first, and try it out
Should I just copy and paste it where my current one is?
Yup! There are two input parameters. First is client_scret, and second one is options for the payment method details
Modified it slightly because my JS file doesn't support types.
let client_secret= setupIntent.client_secret;
let BankAccountProps = {
clientSecret: client_secret,
}
const BankAccountForm = (BankAccountProps) => {
const handleConfirm = async () => {
const stripe = useStripe();
if (!stripe) {
console.log('No stripe');
}
const result = await stripe.collectBankAccountForSetup(BankAccountForm.clientSecret, {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'Jane Yong',
email: 'test@test.com',
},
},
});
};
};
Still getting the same error 😦
What's the error message?
Hi @umbral wharf I'm taking over this thread
wait
it started working
It doesn't display the modal though
River you are a hero thank you so much for getting me this far
How do I go about getting it to display the modal now?
I was under the impression it'd just show up if I called the collect bank account info item
I'm happy to learn that the problem is resolved.
Feel free to let me know if you have a follow-up question.
Wait I'm still having an issue
How do I get the modal to display now?
const stripePromise = loadStripe();
return (
<div>
<h1>Please link an external bank account!</h1>
<Elements stripe={stripePromise}>
<PaymentElement />
</Elements>
)
here's my current return statement
Hi @umbral wharf It's a long thread, can you give me a quick summary?
Essentially I'm trying to verify peoples external bank accounts to allow for treasury account transfers in and out of the platform. I'm having a very hard time getting the stripe verification modal to show up on my page
I need to link the external bank account to the internal treasury financial account
OK, you mean no dialog is open after calling stripe.collectBankAccountForSetup() ?
right it doesn't display anything
Did you see any error in the browser console?
(node:7164) Stripe: Options found in arguments (stripeAccount). Did you mean to pass an options object? See https://github.com/stripe/stripe-node/wiki/Passing-Options.
(node:7164) Stripe: Invalid options found (attach_to_self, flow_directions, payment_method_types, payment_method_options); ignoring.
(node:7164) Stripe: Options found in arguments (stripeAccount). Did you mean to pass an options object? See https://github.com/stripe/stripe-node/wiki/Passing-Options.
(node:7164) Stripe: Invalid options found (attach_to_self, flow_directions, payment_method_types, payment_method_options); ignoring.
SERVER CONSOLE
Uncaught (in promise) IntegrationError: Missing value for Stripe(): apiKey should be a string.
at Q (v3:1:72155)
at $ (v3:1:72226)
at new t (v3:1:368652)
at as (v3:1:405619)
at initStripe (stripe.esm.js?ef25:101:1)
at eval (stripe.esm.js?ef25:125:1)
CLIENT CONSOLE
So you have problems in both front end and backend. Let's fix the frontend first.
Sounds good.
const stripePromise = loadStripe(process.env.STRIPE_SECRET_KEY);
here's the stripe thing that is giving the frontend the error, or so I think
const stripePromise = loadStripe(process.env.STRIPE_SECRET_KEY);
You should pass the publishable key here, not the secret key
oh ok. hold up while I switch that
IntegrationError: In order to create a payment element, you must pass a valid PaymentIntent or SetupIntent client secret when creating the Elements group.
e.g. stripe.elements({clientSecret: "{{CLIENT_SECRET}}"})
I'm getting this error now
Did you pass in a valid setupIntent_client_secret to elements?
<Elements stripe={stripePromise}>
Here's all that I'm passing currently
What is the proper way to do go about it?
Ah, you also need to pass in a client_secret.
Also I thought the client secret was only necessary for the collectBankAccountForSetup method
Do I need to pass it to the element as well?
clientSecret,
..
}
return (
<Elements options={options} stripe={stripePromise}>
...
Something like this.
const options = {
client_secret
}
<Elements stripe={stripePromise} options={options}>
here's what I went with
By the way I still have the apikey errors in my client console
Did you change it to publishable key?
yep
STRIPE_PUBLISHABLE_KEY=pk_test_51LruhiLQhKtna1xjr08WNjbsmDan9CfuRij30WPNRP2AhmZI5tAdApWHqQcKQ1vHckzI8UImddqSq5BY0E12Tdvh00TRDphdDf
const stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY);
here's the errors I'm getting
Are you using next.js? If so You need to use NEXT_PUBLIC_ prefix for the constants in the .env file (https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser)
Yes!
That fixed those errors we have some new ones but I think we're starting to get somewhere 😅
IntegrationError: In order to create a payment element, you must pass a valid PaymentIntent or SetupIntent client secret when creating the Elements group.
e.g. stripe.elements({clientSecret: "{{CLIENT_SECRET}}"})
Here's the current error
OK. Then you need to create a SetupIntent at your backend, pass the client_secret to frontend so that you can pass it to the elements
That's what I'm doing is the thing
I've confirmed that I'm using the client secret in there because I console.log it on the client side to check
Is it a one time use? I'm currently using it in the collectBankAccountForSetup
seti_1M6TWaPu5lQVhWK8Vq6EMczm_secret_Mq9qj4bIcwZPGekuYYwdYZpqTGnSqfo
here's what the most recent one looked like
const BankAccountForm = (BankAccountProps) => {
const handleConfirm = async () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const stripe = useStripe();
if (!stripe) {
console.log('No stripe');
}
const result = await stripe.collectBankAccountForSetup(BankAccountForm.clientSecret, {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'Jane Yong',
email: 'test@test.com',
},
},
});
};
};
here's the current bank account form function
Did you pass the client_secret to <Elements> ?
Yes I did so via the options
console.log(client_secret);
const options = {
client_secret
}
<Elements stripe={stripePromise} options={options}>
<PaymentElement />
</Elements>
here's my elements tags
const setupIntent = await stripe.setupIntents.create({
stripeAccount: dbUser.connectAccountID,
attach_to_self: true,
flow_directions: ['inbound', 'outbound'],
payment_method_types: ['us_bank_account'],
payment_method_options: {us_bank_account: {verification_method: "automatic"}}
});
let client_secret= setupIntent.client_secret;
let BankAccountProps = {
clientSecret: client_secret,
}
here's my setup intent
Wait a second, actually you don't need to use Stripe elements.
How do I go about it wise one?
You just need to pass the setup_intent_client_secret to stripe.collectBankAccountForSetup()
I'm already doing that am I not?
You can just follow this doc (https://stripe.com/docs/payments/ach-debit/set-up-payment)
Right I've tried the stuff in that but can't get it to render. How do I go about getting it to show up?
This is one of the things I'm so confused about
<Elements stripe={stripePromise} options={options}>
<PaymentElement />
</Elements>
Do I need any of this or can I get rid of it all?
If I comment it out then this is the only error I have.
The issue is that it isn't rendering the modal still
Hmm. Are you using any chrome browser plugins?
I'm using adblocker. I just turned it off and no longer have that error. It still isn't rendering though 🫤
here's the current serverside errors
Not sure if you'd really consider those errors though
Can you share with me the server side code?
Yep
Lot's of comments because I'm removing functionality until this modal is working
const setupIntent = await stripe.setupIntents.create({
stripeAccount: dbUser.connectAccountID,
attach_to_self: true,
flow_directions: ['inbound', 'outbound'],
payment_method_types: ['us_bank_account'],
payment_method_options: {us_bank_account: {verification_method: "automatic"}}
});
attach_to_self and flow_directions are not valid params for SetupIntent creation API. Please refer to this API doc for the list of params that it accepts
https://stripe.com/docs/api/setup_intents/create?lang=ruby#create_setup_intent
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Which according to the docs I agree with, however, on this page it says that you're supposed to have them included in order to connect an external bank account for the user https://stripe.com/docs/treasury/examples/moving-money#verifying-an-external-bank-account
Hence why I'm so confused trying to do this😅
I see, these are beta params and not available to everyone yet.
I should be on this beta though is the thing.
Is there a way for you to check if I have access?
At the very least I should have access to the test environment.
I was able to confirm that I do have access in test mode.
This seems like a better guide
Do you know if this still accomplishes the external bank account ownership verification though?
Correction. the attach_to_self and flow_directions are valid params, sorry for my oversights.
Can I have your merchant ID so that I can take a look at the log?
All good. Absolutely one second
acct_1LruhiLQhKtna1xj
This is what you're looking for right?
And also the connected account ID?
Thanks. I think there's a problem with the example code in this doc
const setupIntent = await stripe.setupIntents.create({
attach_to_self: true,
flow_directions: ['inbound', 'outbound'],
payment_method_types: ['us_bank_account'],
payment_method_options: {us_bank_account: {verification_method: "automatic"}}
},{
stripeAccount: dbUser.connectAccountID,
});
Can you change it to this and try again?
yep standby
I'm no longer getting those errors in the console. The issue is the modal still isn't rendering.
What'd you change on the server side?
I'll inform the relevant team to fix the error in this doc, basically the {stripeAccount} should be placed in the second param in order to make an API call on behalf of a connected account https://stripe.com/docs/connect/authentication#stripe-account-header
Oh man. Dang good catch
I'm not getting any errors but I'm still not seeing my modal. Do you know what the issue could be?
And you also need to specify the connected_account ID in your frontend when initializing Stripe.js
const stripePromise = loadStripe('{{PLATFORM_PUBLISHABLE_KEY}}', {
stripeAccount: '{{CONNECTED_STRIPE_ACCOUNT_ID}}',
});
Ok standby while I do that.
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, {stripeAccount: dbUser.connectAccountID});
alright here's how it looks on my end now
Still not seeing the modal fyi
any errors in the browser console?
nope
I'm still not certain where it is supposed to render from because we aren't putting anything into the return statement
Are you sure we don't need this?
{/*<Elements stripe={stripePromise} options={options}>*/}
{/* <PaymentElement />*/}
{/*</Elements>*/}
I've tried uncommenting it and it's still the same error.
There's no error when you call stripe.collectBankAccountForSetup() ?
correct but it looks like it may not even be getting called
const BankAccountForm = (BankAccountProps) => {
const handleConfirm = async () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const stripe = useStripe();
if (!stripe) {
console.log('No stripe');
}
const result = await stripe.collectBankAccountForSetup(BankAccountForm.clientSecret, {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'Jane Yong',
email: 'test@test.com',
},
},
});
};
console.log('in');
};
that console.log isn't printing
It seems like the param names are omitted. Can you add in the param names and try again?
{
clientSecret: '{SETUP_INTENT_CLIENT_SECRET}',
params: {
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {name: 'Jenny Rosen', email: 'jenny@example.com'},
},
},
}
);
// Handle the setupIntent or error
const result = await stripe.collectBankAccountForSetup({
clientSecret: BankAccountForm.clientSecret,
params:{
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'Jane Yong',
email: 'test@test.com',
},
},
},
});
Here's what I updated it to
doesn't appear to have made a difference
const BankAccountForm = async (BankAccountProps) => {
for some reason it isn't going into the bank account form at all
I got rid of it and am getting this error now
let client_secret= setupIntent.client_secret;
let BankAccountProps = {
clientSecret: client_secret,
}
// eslint-disable-next-line react-hooks/rules-of-hooks
const usestripe = useStripe();
const result = await usestripe.collectBankAccountForSetup({
clientSecret: client_secret,
params:{
payment_method_type: 'us_bank_account',
payment_method_data: {
billing_details: {
name: 'Jane Yong',
email: 'test@test.com',
},
},
},
});
here's the current code
Can you upload the whole project to somewhere that I can download? so that I can reproduce the problem at my end.
Yes. Does a zip work?
Sure
account:
sign in with google (you need to access it from the sidebar) the homepage version is deprecated.
That's the test account info
It should automatically take you to the application page, but if not just go /application in the url
Thanks so much for being willing to do this it's really above and beyond
The discord is quite busy at this moment and I may not be able to find a solution today.
Can I suggest you to write in to Stripe support https://support.stripe.com/contact , send them the code and tell them you've talked to the engineers in discord. They'll forward the ticket to us and we'll continue to help you from there.