Getting Started
This guide walks you through installing Shopkeeper, configuring your application, and accepting your first payment.
Installation
Install and configure the package using the following command:
node ace add @foadonis/shopkeeperMigrations
Shopkeeper ships with a set of database migrations that:
- Add billing columns (
stripe_id,trial_ends_at, etc.) to youruserstable - Create a
subscriptionstable to track your customers' subscriptions - Create a
subscription_itemstable for subscriptions with multiple prices - Create a
stripe_webhook_eventstable for idempotent webhook handling
Run the migrations with:
node ace migration:runConfiguration
Billable model
Before using Shopkeeper, add the billable() mixin to your model. This is typically the User model. The mixin provides methods for common billing tasks like creating subscriptions, managing payment methods, and more.
import { compose } from '@adonisjs/core/helpers'
import { BaseModel } from '@adonisjs/lucid/orm'
import { billable } from '@foadonis/shopkeeper/mixins'
export default class User extends compose(BaseModel, billable()) {}Then, define your model as the customer model in the Shopkeeper configuration:
import { defineConfig } from '@foadonis/shopkeeper'
export default defineConfig({
customerModel: () => import('#models/user'),
// ...
})If you use a model with a different name than User, make sure to update the table name in the
generated migration accordingly.
API keys
Configure your Stripe API keys in your application's .env file. You can find your keys in the Stripe dashboard.
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secretThe STRIPE_WEBHOOK_SECRET environment variable is mandatory in production. It secures the Stripe
webhook endpoint and ensures incoming events are authentic.
Webhooks
Register the Shopkeeper webhook route and listeners in your application:
import shopkeeper from '@foadonis/shopkeeper/services/shopkeeper'
shopkeeper.registerRoutes()import shopkeeper from '@foadonis/shopkeeper/services/shopkeeper'
shopkeeper.registerWebhookListeners()Then, use the shopkeeper:webhook Ace command to create the webhook in Stripe with all the required events:
node ace shopkeeper:webhookTo learn more about webhook configuration and handling custom events, see the Handling Webhooks guide.
Your first checkout
Let's accept your first payment using Stripe Checkout, a hosted payment page provided by Stripe.
Create a price
First, create a price for your product in Stripe. You can do this from the Stripe dashboard or using the Stripe CLI:
stripe prices create \
--currency=usd \
--unit-amount=1000 \
-d "recurring[interval]=month" \
-d "product_data[name]=Gold Plan"This creates a recurring price of $10/month. Take note of the price ID (e.g., price_xxxxxxx) returned by Stripe.
Redirect to checkout
Create a route that redirects your user to the Stripe Checkout page:
import router from '@adonisjs/core/services/router'
import { urlFor } from '@adonisjs/core/services/url_builder'
router.get('/checkout', async ({ auth, response }) => {
const user = auth.getUserOrFail()
const checkout = await user.newSubscription('default', 'price_xxxxxxx').checkout({
success_url: urlFor('checkout.success'),
cancel_url: urlFor('checkout.cancel'),
})
return response.redirect().status(303).toPath(checkout.asStripeSession().url)
})Handle the redirect
When a customer completes or cancels their purchase, Stripe redirects them back to your application. Create routes to handle both cases:
router
.get('/checkout/success', async ({ view }) => {
return view.render('checkout/success')
})
.as('checkout.success')
router
.get('/checkout/cancel', async ({ view }) => {
return view.render('checkout/cancel')
})
.as('checkout.cancel')That's it! Visit /checkout in your browser and you should be redirected to Stripe's payment page. After completing the payment, Stripe will redirect back to your success page.
Stripe and Shopkeeper update subscription statuses via webhooks. There may be a short delay before the subscription is active in your database after the customer completes their payment.
What's next?
Now that you have a working checkout, explore the guides to build on top of it:
- Accepting Payments: Learn about the different ways to collect payments
- Managing Subscriptions: Change plans, cancel, resume, and more
- Managing Customers: Customer management, billing portal, and tax IDs
- Offering Trials: Give your customers a free trial period
- Handling Webhooks: React to Stripe events in your application
- Invoices & Receipts: Show billing history to your customers