Allow creating stripe trial subscription without checkout #1918

Closed
opened 2026-03-13 09:12:36 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @maulik13 on GitHub (Sep 13, 2025).

Is this suited for github?

  • Yes, this is suited for github

For a trial of a SaaS product we want to make it as easy as possible to get started. Hence I believe that we should not ask users to go through the checkout form just to start a trial.

Example workflow,

  1. User clicks on Register for a trial button
  2. User fills out a form (user info, password, company name)
  3. User clicks on "Start trial"

Describe the solution you'd like

Upon clicking the "Start trial" button I would like to call a better-auth API that creates a subscription with trial without going through a checkout process. We should not need to ask for credit-card either to make it easier to try out a product. When the trial runs out, the user would have to upgrade the subscription.

Describe alternatives you've considered

Write my own stripe API calls to create a subscription without going through a checkout session. However, in this case we do not have a good integration with better-auth and if we want to make it work we need to add a lot of custom code which might break if better-auth implementation changes.

Additional context

No response

Originally created by @maulik13 on GitHub (Sep 13, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. For a trial of a SaaS product we want to make it as easy as possible to get started. Hence I believe that we should not ask users to go through the checkout form just to start a trial. Example workflow, 1. User clicks on Register for a trial button 2. User fills out a form (user info, password, company name) 3. User clicks on "Start trial" ### Describe the solution you'd like Upon clicking the "Start trial" button I would like to call a better-auth API that creates a subscription with trial without going through a checkout process. We should not need to ask for credit-card either to make it easier to try out a product. When the trial runs out, the user would have to upgrade the subscription. ### Describe alternatives you've considered Write my own stripe API calls to create a subscription without going through a checkout session. However, in this case we do not have a good integration with better-auth and if we want to make it work we need to add a lot of custom code which might break if better-auth implementation changes. ### Additional context _No response_
GiteaMirror added the enhancement label 2026-03-13 09:12:36 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Dec 13, 2025):

Hi, @maulik13. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You requested a feature to create Stripe trial subscriptions directly via the API, bypassing checkout and credit card steps.
  • The goal is to have trials start immediately after registration and delay subscription upgrades until after the trial ends.
  • Currently, you use custom Stripe API calls outside of better-auth, which may break with future updates.
  • No further comments or activity have been recorded on this request.

Next Steps

  • Please let me know if this feature request is still relevant to the latest version of better-auth by commenting on this issue.
  • If I do not hear back within 7 days, I will automatically close this issue.

Thank you for your understanding and contribution!

@dosubot[bot] commented on GitHub (Dec 13, 2025): Hi, @maulik13. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You requested a feature to create Stripe trial subscriptions directly via the API, bypassing checkout and credit card steps. - The goal is to have trials start immediately after registration and delay subscription upgrades until after the trial ends. - Currently, you use custom Stripe API calls outside of better-auth, which may break with future updates. - No further comments or activity have been recorded on this request. **Next Steps** - Please let me know if this feature request is still relevant to the latest version of better-auth by commenting on this issue. - If I do not hear back within 7 days, I will automatically close this issue. Thank you for your understanding and contribution!
Author
Owner

@michalkow commented on GitHub (Dec 30, 2025):

I had a similar problem. I wanted to automatically add customers to the trial plan when they sign up, without collecting CC details. I solved it with a hook, maybe the following example will be useful to someone with sthe ame issue:

// I define plans that will pass to Stripe Plugin - makes it easier to just extract trial plan later
const plans = [{
  name: "My Standard Plan with Trial", // the name of the plan, it'll be automatically lower cased when stored in the database
  priceId: "price_stripe_key_1", // the price ID from stripe
  annualDiscountPriceId: "price_stripe_key_2", // (optional) the price ID for annual billing with a discount
  freeTrial: {
    days: 14,
  },
},
{
  name: "My Awesome Pro Plan", 
  priceId: "price_stripe_key_3", 
  annualDiscountPriceId: "price_stripe_key_4", 
}]

// Stripe Plugin Configuration
stripe({
  // We will use stripeClient in onCustomerCreate hook
  stripeClient,
  stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  createCustomerOnSignUp: true,
  subscription: {
    enabled: true,
    plans,
  },
  onCustomerCreate: async ({ stripeCustomer, user }, ctx) => {
    // Extract trial plan from plans array, you can add find by name or priceId logic here
    const trial = plans[0];

    const stripeSubscription = await stripeClient.subscriptions.create({
      customer: stripeCustomer.id,
      items: [{ price: trial.priceId, quantity: 1 }], // quantity = seats if you want
      trial_period_days: trial.freeTrial.days,
      trial_settings: {
        end_behavior: {
          missing_payment_method: "cancel",
        },
      },
    });

    // Borrowed from Stripe Plugin code
    await ctx.context.adapter.create({
      model: "subscription",
      data: {
        stripeCustomerId: stripeCustomer.id,
        referenceId: user.id,
        status: stripeSubscription.status,
        seats: stripeSubscription.items.data[0]?.quantity || 1,
        plan: trial.name.toLowerCase(),
        periodEnd: new Date(stripeSubscription.items.data[0]?.current_period_end! * 1000),
        periodStart: new Date(
          stripeSubscription.items.data[0]?.current_period_start! * 1000
        ),
        stripeSubscriptionId: stripeSubscription.id,
        cancelAtPeriodEnd: stripeSubscription.cancel_at_period_end,
        cancelAt: stripeSubscription.cancel_at
          ? new Date(stripeSubscription.cancel_at * 1000)
          : null,
        canceledAt: stripeSubscription.canceled_at
          ? new Date(stripeSubscription.canceled_at * 1000)
          : null,
        ...(stripeSubscription.trial_start && stripeSubscription.trial_end
          ? {
              trialStart: new Date(stripeSubscription.trial_start * 1000),
              trialEnd: new Date(stripeSubscription.trial_end * 1000),
            }
          : {}),
      },
    });
    
  }
})
@michalkow commented on GitHub (Dec 30, 2025): I had a similar problem. I wanted to automatically add customers to the trial plan when they sign up, without collecting CC details. I solved it with a hook, maybe the following example will be useful to someone with sthe ame issue: ```javascript // I define plans that will pass to Stripe Plugin - makes it easier to just extract trial plan later const plans = [{ name: "My Standard Plan with Trial", // the name of the plan, it'll be automatically lower cased when stored in the database priceId: "price_stripe_key_1", // the price ID from stripe annualDiscountPriceId: "price_stripe_key_2", // (optional) the price ID for annual billing with a discount freeTrial: { days: 14, }, }, { name: "My Awesome Pro Plan", priceId: "price_stripe_key_3", annualDiscountPriceId: "price_stripe_key_4", }] // Stripe Plugin Configuration stripe({ // We will use stripeClient in onCustomerCreate hook stripeClient, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, createCustomerOnSignUp: true, subscription: { enabled: true, plans, }, onCustomerCreate: async ({ stripeCustomer, user }, ctx) => { // Extract trial plan from plans array, you can add find by name or priceId logic here const trial = plans[0]; const stripeSubscription = await stripeClient.subscriptions.create({ customer: stripeCustomer.id, items: [{ price: trial.priceId, quantity: 1 }], // quantity = seats if you want trial_period_days: trial.freeTrial.days, trial_settings: { end_behavior: { missing_payment_method: "cancel", }, }, }); // Borrowed from Stripe Plugin code await ctx.context.adapter.create({ model: "subscription", data: { stripeCustomerId: stripeCustomer.id, referenceId: user.id, status: stripeSubscription.status, seats: stripeSubscription.items.data[0]?.quantity || 1, plan: trial.name.toLowerCase(), periodEnd: new Date(stripeSubscription.items.data[0]?.current_period_end! * 1000), periodStart: new Date( stripeSubscription.items.data[0]?.current_period_start! * 1000 ), stripeSubscriptionId: stripeSubscription.id, cancelAtPeriodEnd: stripeSubscription.cancel_at_period_end, cancelAt: stripeSubscription.cancel_at ? new Date(stripeSubscription.cancel_at * 1000) : null, canceledAt: stripeSubscription.canceled_at ? new Date(stripeSubscription.canceled_at * 1000) : null, ...(stripeSubscription.trial_start && stripeSubscription.trial_end ? { trialStart: new Date(stripeSubscription.trial_start * 1000), trialEnd: new Date(stripeSubscription.trial_end * 1000), } : {}), }, }); } }) ```
Author
Owner

@maulik13 commented on GitHub (Jan 2, 2026):

I ended up writing my own Stripe integration code using help from Claude. It did end up adding a lot of code, but I got more flexibility in handling changes according to how I wanted.

@maulik13 commented on GitHub (Jan 2, 2026): I ended up writing my own Stripe integration code using help from Claude. It did end up adding a lot of code, but I got more flexibility in handling changes according to how I wanted.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1918