Skip to content

Payments + Plans

StartKit.AI uses either Stripe or Lemon Squeezy for your payment provider and we have setup instructions for both.

Stripe

  1. Make sure you have your Stripe Account set up for receiving payments.
  2. Turn on Stripe’s Test Mode
  3. Create a new product and copy the Price ID

How to find the Stripe price id

  1. Paste the Price ID into the config/plans.yml file for the respective plan, in the price_id field.

Stripe Webhooks

Webhooks are how Stripe lets you know that you’ve received a payment. In the case of StartKit.AI, we have an API route that you can provide to Stripe which will provision a users’ account after they pay using the limits set in the plans.yml file.

  1. Go to Developers -> API Keys and copy the Secret key, enter it into your .env
.env
STRIPE_API_KEY=
  1. Go to Developers -> Webhooks and add the endpoint for https://<your_startkit_url>/api/webhooks/payments (you can change this url later if you don’t know your domain yet).

You should listen to the following events at a minimum (you can add more later if you want):

  • checkout.session.completed
  • customer.subscription.deleted
  • customer.subscription.updated

Payment links are the quickest way to direct a customer to a checkout page with Stripe.

  1. Go to Payment Links
  2. Create a payment link for each of your products.

stripe-checkout-1

  1. Click the After payment tab, select Don’t show confirmation page, and set the checkout to redirect back to StartKit: https://localhost:1337/app/settings/plan

stripe-checkout-2

  1. Click Create link in the top right and paste the payment link into the config/plans.yml file for the respective plan, in the checkout_url field.
checkout_url: https://buy.stripe.com/test_3cs4jVgd1euY5y08wA

Customer Portal

The Stripe customer portal is the best way to let customers manage their subscription and billing details.

  1. Go to Customer Portal
  2. Activate your test link
  3. Paste the link into your .env as the VITE_CUSTOMER_PORTAL_URL
VITE_CUSTOMER_PORTAL_URL=

stripe-portal

Testing locally in development

It’s possible to test the Stripe webhooks locally by using the Stripe CLI.

  1. Install Stripe CLI (more install instructions here).
brew install stripe/stripe-cli/stripe
  1. In the Stripe dashboard go to Developers -> Webhooks -> Add an endpoint -> Test in a local environment.
  2. After logging into the Stripe CLI run this command to forward Stripe webhook events to your local server:
stripe listen --forward-to localhost:1337/api/webhooks/payments
  1. Copy the signing secret from the CLI and enter it into your .env
.env
STRIPE_WEBHOOK_SECRET=

Now you can either trigger events manually with the CLI:

stripe trigger payment_intent.succeeded

Or you can test purchasing a plan using Stripe test payment methods.

In production

  1. In test mode of the Stripe Dashboard, copy your products to live mode and copy the Price ID into your plans.yaml file (see the Stripe Setup section above).
  2. Copy your payment links to live mode and edit the After payment url redirect for each one to your live url https://<your_startkit_url>/app/settings/plan.
  3. Turn off test mode in your Stripe dashboard.
  4. In Settings -> Billing -> Customer portal activate the live link and add it to VITE_CUSTOMER_PORTAL_URL in your producrtion environment variables.
  5. In Developers -> API Keys copy the Secret key and add it to STRIPE_API_KEY= in your production environment variables.
  6. In Developers -> Webhooks create the live webhook at https://<your_startkit_url>/api/webhooks/payments if you haven’t already. Click the webhook, reveal the live signing secret, and enter in STRIPE_WEBHOOK_SECRET= in your production environment variables.
.env.production
STRIPE_API_KEY=
STRIPE_WEBHOOK_SECRET=

Stripe Webhook Events

StartKit.AI implements the following Stripe webhooks and actions them:

/server/api/webhooks/stripe.js
switch (type) {
case 'checkout.session.completed': {
// ✨ The user completed the checkout and paid successfully
// Here we provision access to your product based on the Stript product ID
handleCheckoutCompleted(data.object);
break;
}
case 'checkout.session.expired': {
// ⏲️ The user opened the checkout but did not complete the payment
// (optional): Send a cart expired email
break;
}
case 'customer.subscription.updated': {
// 🔀 The user changed their subscription.
// If the plan was upgraded or downgraded then we update the limits
//
// If the plan was canceled we make a note of this on the user
// as this event is received before the end of the cencellation
// period. A 'customer.subscription.deleted' event will be fired
// when the billing period is finished
// This means you can handle when an account is coming up for cancellation
//
// If the plan was reactivated after being cancelled then we make a note
// of this on the user and ignore the subscription cancelled event from before.
handleSubscriptionUpdated(data.object, data.previous_attributes);
break;
}
case 'customer.subscription.deleted': {
// ❌ The user deleted their subscription
// We remove the users' access to the product
handleSubscriptionDeleted(data.object);
break;
}
}

Feel free to add any other webhook actions that you need into this switch statement.

Lemon Squeezy

  1. Make sure you have your Lemon Squeezy Account set up for receiving payments.
  2. Turn on Lemon Squeezy’s test mode (this is turned on by default if you didn’t set your store live yet).
  3. Create a new product and copy the Product ID.

How to find the Lemon Squeezy product id

  1. Paste the Product ID into the config/plans.yml file for the respective plan, in the price_id field (StartKit uses the price_id variable name but we need the Product Id from Lemon Squeezy).

Creating checkouts

Checkout links are the quickest way to direct a customer to a checkout page with Lemon Squeezy.

  1. Go to your products.
  2. Edit each product, open the settings for Confirmation Modal, and set the Button link to redirect back to StartKit. Lemon Squeezy only allows https links so to test in development you’ll need to use a tool like ngrok to forward the requests to your local environment.

lemonsqueezy-checkout-1

  1. Save the changes and then from the list view click Share next to each product and copy the checkout link:

lemonsqueezy-checkout-2

  1. Paste the checkout link into the config/plans.yml file for the respective plan, in the checkout_url field.

Customer Portal

The Lemon Squeezy customer portal is lets customers self-manage their subscriptions from your store.

  1. Go to Stores to get your store name
  2. Your customer portal URL will be https://[STORE].lemonsqueezy.com/billing so ours would be https://startkitai.lemonsqueezy.com/billing

lemonsqueezy-portal

  1. Paste the link into your .env as the VITE_CUSTOMER_PORTAL_URL
VITE_CUSTOMER_PORTAL_URL=

Lemon Squeezy Webhooks

Webhooks are how Lemon Squeezy lets you know that you’ve received a payment. In the case of StartKit.AI, we have an API route that you can provide to Lemon Squeezy which will provision a users’ account after they pay using the limits set in the plans.yml file.

  1. Go to Settings -> API, create an API key and enter it into your .env
.env
LEMONSQUEEZY_API_KEY=
  1. Go to Settings -> Webhooks and add the endpoint for https://<your_startkit_url>/api/webhooks/payments (you can change this url later if you don’t know your domain yet).

Generate a signing secret like this:

Terminal window
openssl rand -base64 24 | tr -dc A-Za-z0-9 | head -c 40

Enter the signing secret into both your webhook setup and your .env:

.env
LEMONSQUEEZY_WEBHOOK_SECRET=

You should listen to the following events at a minimum (you can add more later if you want):

  • subscription_created
  • subscription_updated
  • subscription_cancelled
  • subscription_resumed
  • subscription_expired

Testing locally in development

It’s possible to test the Lemon Squeezy webhooks locally by using a tool like ngrok to forward the requests to your localhost URL.

Or you can simulate webhook events from the Lemon Squeezy dashboard - see their developer guide for more information.

In production

  1. In test mode of the Lemon Squeezy Dashboard, copy your products to live mode and copy the Product IDs into your plans.yaml file (see the Lemon Squeezy Setup section above).
  2. Copy your checkout links to live mode and edit the confirmation modal button link redirect for each one to your live url https://<your_startkit_url>/app/settings/plan.
  3. Turn off test mode in your Stripe dashboard.
  4. In Settings -> API create a production API key and add it to LEMONSQUEEZY_API_KEY= in your production environment variables.
  5. In Settings -> Webhooks create the live webhook at https://<your_startkit_url>/api/webhooks/payments if you haven’t already. Copy the live signing secret you enter, and enter in LEMONSQUEEZY_WEBHOOK_SECRET= in your production environment variables.
.env.production
LEMONSQUEEZY_API_KEY=
LEMONSQUEEZY_WEBHOOK_SECRET=

Lemon Squeezy Webhook Events

StartKit.AI implements the following Lemon Squeezy webhooks and actions them:

/server/api/webhooks/lemonsqueezy.js
switch (meta.event_name) {
case 'subscription_created': {
// The user completed the checkout and paid successfully
// ✨ Provision access to your product
await handleCheckoutCompleted(data.attributes);
break;
}
case 'subscription_updated': {
// The user changed their subscription.
// ✨ If the plan was upgraded or downgraded change access to your product
handleSubscriptionUpdated(data.attributes);
break;
}
case 'subscription_cancelled': {
// The user canceled their subscription
// Set the subscription to canceled but keep access until the end date
handleSubscriptionCanceled(data.attributes);
break;
}
case 'subscription_resumed': {
// The user resumed a previously canceled subscription
// Set the subscription to resumed and remove end date
handleSubscriptionReactivated(data.attributes);
break;
}
case 'subscription_expired': {
// The user deleted their subscription
// 🚫 Remove access to your product
handleSubscriptionDeleted(data.attributes);
break;
}
}

Feel free to add any other webhook actions that you need into this switch statement.