Skip to content

Stripe + Plans

Usage Limits are controlled by Stripe Plans. This allows you to easily link daily and monthly usage of your customers up with Stripe subscriptions.


Limits for each Plan are handled via the config/plans.yml file. In this file you’ll find three example plans, “Free”, “Basic”, and “Pro”.

default_plan_id: 1
- name: Basic
id: 1
stripe_price_id: price_1Ot87pHfaj3DTrBx6Ux3QUkb
price: 19
total_requests: 100
total_cost: 10
total_requests: 1000
chat_requests: 100
tts_requests: 100
image_requests: 50
vision_requests: 50

Limit types

There are two global types that you can limit, total requests and total cost:

  • total_requests — The total number of requests of any type that a user can make
  • total_cost — The total spend a user can accumulate in AI fees (in USD).

You can then specify limits on requests and cost for each type of AI API endpoint:

  • chat_requests — The total number of requests to the /api/chat endpoint
  • chat_cost — The total cost incurred by querying the /api/chat endpoint

Valid API limit properties are:

  • chat_requests
  • chat_cost
  • tts_requests
  • tts_cost
  • image_requests
  • image_cost
  • vision_requests
  • vision_cost

If you don’t want a limit for a specific type of request then you can omit it and it will be considered to be Infinity. If you want a plan with no limits at all, then you can omit the limits property entirely.


So for example, if you wanted to limit your customers to 10 chat requests and 5 images created per day, but also make sure they don’t exceed US$50 in costs per month you would set the plan like this:

name: Pro
id: 1
chat_requests: 10
image_requests: 5
total_cost: 50

Stripe Setup

  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 price id

  1. Paste the Price ID into the config/plans.yml file for the respective plan, in the stripe_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
  1. Go to Developers -> Webhooks and add the endpoint for https://<your_startkit_url>/api/webhooks/stripe (you can change this url later if you don’t know your domain yet).

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/stripe
  1. Copy the signing secret from the CLI and enter it into your .env

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. Turn off test mode in your Stripe dashboard.
  3. In Developers -> API Keys copy the Secret key and add it to STRIPE_API_KEY= in your production environment variables.
  4. In Developers -> Webhooks create the live webhook at https://<your_startkit_url>/api/webhooks/stripe if you haven’t already. Click the webhook, reveal the live signing secret, and enter in STRIPE_WEBHOOK_SECRET= in your production environment variables.


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

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
case 'checkout.session.expired': {
// ⏲️ The user opened the checkout but did not complete the payment
// (optional): Send a cart expired email
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);
case 'customer.subscription.deleted': {
// ❌ The user deleted their subscription
// We remove the users' access to the product

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

Admin Dashboard

Usage limits for individual customers can be managed from within the Admin Dashboard