Usually when you’re building an app for business, you need to interface with charging money.
It’s gotten a lot easier to charge a one-time fee or start a subscription. But, there are some core things you can do in your apps to make life easier.
One thing I like to do when it comes to either a Stripe checkout or a credit-card update portal is to look at the type of card the user is inputing.
The Stripe card object has a property called
funding. This parameter will either be
pre-paid. (There can also be an unknown value.)
If the user is inputing a
pre-paid type, I typically will either decline these and pass a message to the user. Or, I’ll push something to the main company CRM.
For most B2B businesses, these type of cards are death. 😵
Free trials have the potential to bring in low quality users. One technique you can imploy to only allow trials for legitimate users is to pre-authorize the cards before allowing the free trial.
When authorizing chargs, the card issuer is basically guaranteeing the user has enough funds to cover the purchase.
This is particularly useful when your free trial includes the ability to easily upgrade your account.
For example, let’s say the user has a 14 day free trial. And, you charge $20/mn/user.
If the user adds 100 users during the trial, you charge nothing and they basically own you $2,000 after the 14 days.
Depending on how much those 100 users cost you as a business, you may wish to pre-auth the card before letting them add them.
This will ensure you are more likely to collect that $2,000 at the end of the 14 days. It also hardens your app against those wishing to perform malicious activity.
One of the pains when developing applications that have users/features tied to billing logic, is the need to have the same product & plan names in both testing and production.
Stripe requires you to specify the plan and product names when applying purchases. And, while you could look this up by searching for a price or something, that’d create a much longer call and hamstring your app.
What I prefer to do is write a
setup command, that checks for all required Stripe plan and product names on entering a new enviroment. Think of it as something similar to a database migration.
In this setup call, I basically just try to retrieve the plan inside of a try/catch statement. If an error is caught, the plan doesn’t exist and I know to create it.
I then also include business data in my array of plan names like user limit or something. Then, I can find the correct plan ID in my stripe controllers from the array. Thus, detaching my code from the stripe plan name even more.
When creating, updating or adding subscriptiongs, I typically queue these calls.
You can use Beanstalkd or whatever your favorite queue handler is.
Stripe, while fast and reliable, does have downtime and can slow down a process like registration. I shoot for 250-300ms response times on all endpoints. So, I typically end up creating a customer and then queuing the rest of the work.
A simple try/catch won’t work with Stripe. I found this a little hard to find the first time I was looking through the API docs.
Here is a list of all the exceptions you should listen for on any subscription change or card charge:
This will allow you to give the user a good description as to why their card was not accepted.
Finally, be sure to take advantage of Stripe’s webhook system. You should build an endpoint into your app that accepts all of your Stripe accounts data.
From here, you can get real-time updates when a card fails, customer disputes, or subscription is cancelled. This is the easiest way to make sure you always shutdown user’s when their accounts fail.