#marcoprouve-express-onboarding
1 messages ยท Page 1 of 1 (latest)
Hello!
For tracking the ability to accept payouts you'll want to listen for the account.updated event and check whether payouts_enabled is true (see https://stripe.com/docs/api/accounts/object#account_object-payouts_enabled)
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
For tracking whether the account has gone through setup you'll want to check details_submitted (https://stripe.com/docs/api/accounts/object#account_object-details_submitted)
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Thank you so much! One more thing just to clarify. Im assuming creating account links should be done pretty frequently? Should I be creating an account link every time a user clicks the button to update or setup their stripe account?
As a user: I sort of have a multi-stage process - I have an "account"page where I gather a lot of information on my own platform, keeping the user informed of what might be missing (address, email, phone number, etc). I don't present a button for the onboarding link (just a place-holder) until what information I can collect has been collected. messages below this inform the user of what's missing.
After that, I check the status of their account (I have a couple server-side routines for this), and re-present the onboarding link if they haven't completed it.
When onboarded, I present an account link (separate API call) for them to access their limited dashboard. I also add notes below this button/link to give them a summary of what they need to update to stay current.
I could share my server-side checks, if you want.
Thank you sorry on a call quick but will respond when done ๐
@worthy flume Thank you for the response this helps a lot!
my routine is pretty brute force (there really isn't another way), but I can show you some of them if you want...
For the Stripe account status, I pull an account object from the API, and send it to:
/**
* Builds a status report of open and pending issues for an account
* @async
* @function
* @param {accountHash} paymentAccount
* @returns {string} text report
*/
export const stripeAccountStatusReport = (paymentAccount) => {
return statusSummary({
requirements: paymentAccount.requirements,
tos_acceptance: paymentAccount.tos_acceptance,
details_submitted: paymentAccount.details_submitted,
future_requirements: paymentAccount.future_requirements,
payouts_enabled: paymentAccount.payouts_enabled
});
};
...just pulling out the relevant sections. This gets sent to a summary routine (following)
This gets built up into a string (not an object) as so:
/**
* @function
* @param {accountStatusHash} accountStatus
* @returns {string}
*/
export const statusSummary = (accountStatus) => {
let returnString = "";
returnString = returnString.concat(
requirementsSummary(
`Your Account has issues that must be resolved`,
accountStatus.requirements
)
);
returnString = returnString.concat(
requirementsSummary(
`Your Account has issues that will need resolved`,
accountStatus.future_requirements
)
);
return returnString;
};
The requirements part (which is similar between current and future) is:
const requirementsSummary = (msg, requirements) => {
let returnString = "";
if (requirements?.disabled_reason) {
returnString = `\n${msg} immediately\n`;
returnString = requirements.past_due.reduce((result, due) => {
return result.concat(`=> ${due}\n`);
}, returnString);
return returnString;
}
if (requirements?.current_deadline) {
returnString = `\n${msg} by ${dayjs
.unix(requirements?.current_deadline)
.format("MMM DD, YYYY")}\n`;
returnString = requirements.currently_due.reduce((result, due) => {
return result.concat(`=> ${due}\n`);
}, returnString);
if (requirements?.errors?.length) {
returnString = returnString.concat(
`\nThese requirements were in part caused by the following errors:\n`
);
returnString = requirements.errors.reduce((result, error) => {
return result.concat(`=> ${error.requirement}: ${error.reason}\n`);
}, returnString);
}
}
return returnString;
};
Oh this is very helpful, I was only going o check payout_enabled and details_provided
you use tos_acceptance and future_requirements checks, what are these for?
And finally, to respond to account.update events, I set a flag in my database accounts::
/**
* Responds to account.updated events.
* If the status has any issues to report, the application account will
* add a flag {openIssues: true}
* If the status has no issues to report, the application account will
* add a flag {openIssues: false}
* Management systems can query for {openIssues: true} to find delinquent
* accounts; both missing flag and {openIssues: false} will be ignored
* @async
* @function
* @param {accountHash} paymentAccount
* @returns {null}
*/
export const accountUpdate = async (paymentAccount) => {
const statusReport = await stripeAccountStatusReport(paymentAccount);
const businessRefPath = paymentAccount.metadata.account_refPath;
const business_account = refPathToBaseRecord(businessRefPath);
if (statusReport && statusReport.length) {
return setOpenIssues(business_account);
//set {openIssues: true} in application account.
} else {
return clearOpenIssues(business_account);
}
};
This is extremely helpful. Definitely wouldnt have checked requirements until i figured out the use case later
thank you ๐
tos_acceptance is whether they have accepted "Terms of Service", which can change if there's a change in their bank account or debit. future_requirements is same as current requirements, but may be more based on things like rising account volume, etc
Got it
Basically, I'm trying to let them know what to go fix, rather than just signalling "It broke. Go Fix."
Yeah for sure, Thats always better
I also use a single entry-point/call for onboarding & account link, which is differentiated with
paymentAccount.requirements?.disabled_reason
i.e. if disabled for any reason (or not enabled yet) send them to onboarding
the status report gets sent back with the requested link for display
well, it seems to differentiated onboarded accounts and not onboarded accounts