Customers
Retrieving Customers
You can retrieve a customer by their Stripe ID using the shopkeeper.findBillable
method. This method will return an instance of the billable model:
import shopkeeper from '@foadonis/shopkeeper/services/shopkeeper'
const user = await shopkeeper.findBillable(stripeId)
Creating Customers
Occasionally, you may wish to create a Stripe customer without beginning a subscription. You may accomplish this using the createAsStripeCustomer
method:
const stripeCustomer = await user.createAsStripeCustomer()
Once the customer has been created in Stripe, you may begin a subscription at a later date. You may provide an optional params
argument to pass in any additional customer creation parameters that are supported by the Stripe API:
const stripeCustomer = await user.createAsStripeCustomer(params)
You may use the asStripeCustomer
method if you want to return the Stripe customer object for a billable model:
const stripeCustomer = await user.asStripeCustomer()
The createOrGetStripeCustomer
method may be used if you would like to retrieve the Stripe customer object for a given billable model but are not sure whether the billable model is already a customer within Stripe. This method will create a new customer in Stripe if one does not already exist:
const stripeCustomer = await user.createOrGetStripeCustomer()
Updating Customers
Occasionally, you may wish to update the Stripe customer directly with additional information. You may accomplish this using the updateStripeCustomer
method. This method accepts as an argument the customer update options supported by the Stripe API:
const stripeCustomer = await user.updateStripeCustomer(params)
Balances
Stripe allows you to credit or debit a customer's "balance". Later, this balance will be credited or debited on new invoices. To check the customer's total balance you may use the balance
method that is available on your billable model. The balance
method will return a formatted string representation of the balance in the customer's currency:
const balance = await user.balance()
To credit a customer's balance, you may provide a value to the creditBalance
method. If you wish, you may also provide a description:
await user.creditBalance(500, 'Premium customer top-up')
Providing a value to the debitBalance
method will debit the customer's balance:
await user.debitBalance(500, 'Premium customer top-up')
The applyBalance
method will create new customer balance transactions for the customer. You may retrieve these transaction records using the balanceTransactions
method, which may be useful in order to provide a log of credits and debits for the customer to review:
// Retrieve all transactions...
const transactions = await user.balanceTransactions()
for (const transaction of transactions) {
const amount = transaction.amount() // $2.31
// Retrieve the related invoice when available...
const invoice = await transaction.invoice()
}
Tax IDs
Shopkeeper offers an easy way to manage a customer's tax IDs. For example, the taxIds
method may be used to retrieve all of the tax IDs that are assigned to a customer as a collection:
const taxIds = await user.taxIds()
You can also retrieve a specific tax ID for a customer by its identifier:
const taxId = await user.findTaxId('txi_belgium')
You may create a new Tax ID by providing a valid type and value to the createTaxId
method:
const taxId = await user.createTaxId('eu_vat', 'BE0123456789')
The createTaxId
method will immediately add the VAT ID to the customer's account. Verification of VAT IDs is also done by Stripe; however, this is an asynchronous process. You can be notified of verification updates by subscribing to the customer.tax_id.updated
webhook event and inspecting the VAT IDs verification
parameter. For more information on handling webhooks, please consult the documentation on defining webhook handlers.
You may delete a tax ID using the deleteTaxId
method:
await user.deleteTaxId('eu_vat')
Syncing Customer Data With Stripe
Typically, when your application's users update their name, email address, or other information that is also stored by Stripe, you should inform Stripe of the updates. By doing so, Stripe's copy of the information will be in sync with your application's.
To automate this, you may define an event listener on your billable model that reacts to the model's updated
event. Then, within your event listener, you may invoke the syncStripeCustomerDetails
method on the model:
import { BaseModel, afterCreate } from '@adonisjs/lucid/orm'
export default class User extends compose(BaseModel, Billable) {
@afterUpdate()
static synchWithStripe(user: User) {
user.syncStripeCustomerDetails()
}
}
Now, every time your customer model is updated, its information will be synced with Stripe. For convenience, Shopkeeper will automatically sync your customer's information with Stripe on the initial creation of the customer.
You may customize the columns used for syncing customer information to Stripe by overriding a variety of methods provided by Shopkeeper. For example, you may override the stripeName
method to customize the attribute that should be considered the customer's "name" when Shopkeeper syncs customer information to Stripe:
import { BaseModel, afterCreate } from '@adonisjs/lucid/orm'
export default class User extends compose(BaseModel, Billable) {
stripeName(): string {
return `${this.firstName} ${this.lastName}`
}
}
Similarly, you may override the stripeEmail
, stripePhone
, stripeAddress
, and stripePreferredLocales
methods. These methods will sync information to their corresponding customer parameters when updating the Stripe customer object. If you wish to take total control over the customer information sync process, you may override the syncStripeCustomerDetails
method.
Billing Portal
Stripe offers an easy way to set up a billing portal so that your customer can manage their subscription, payment methods, and view their billing history. You can generate URLs for your users to the billing portal by invoking the billingPortalUrl
method on the billable model from a controller or route:
You may provide a custom URL that the user should return to by passing the URL as an argument to the billingPortalUrl
method:
import router from '@adonisjs/core/services/router'
router
.get('/billing', ({ auth, response }) => {
const user = auth.getUserOrFail()
const billingPortalUrl = await user.billingPortalUrl(route('dashboard'))
response.redirect().toPath(billingPortalUrl)
})
.middleware(middleware.auth())
.name('billing')