Offer a free trial

Offer a free trial — a runnable, end-to-end guide verified against the VINR sandbox.

View as MarkdownInstall skills

A free trial lets a customer use a paid plan before they're charged. This guide creates a trialing subscription, shows both trial styles VINR supports, and handles the moment the trial ends — runnable against the sandbox.

Trial modelsAsk

VINR supports two trial shapes. Pick based on whether you collect a payment method up front.

ModelCard required?Behavior at trial end
No card up frontNoSubscription pauses; customer must add a method to continue.
Card up frontYesSubscription auto-converts and the first invoice is charged.

Card-up-front trials convert at much higher rates and let you charge the moment the trial ends. No-card trials reduce signup friction. The flows below cover both.

A trial is just a subscription with a trialPeriodDays (or explicit trialEnd). No separate "trial" object exists — the subscription's status is trialing until the trial ends, then transitions to active, past_due, or paused.

Create a trial subscriptionAsk

On your backend, create the subscription against an existing price. Set trialPeriodDays to start the customer in trialing with no immediate charge.

import { Vinr } from '@vinr/sdk';

const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

export async function POST(req: Request) {
  const { customerId } = await req.json();

  const subscription = await vinr.subscriptions.create(
    {
      customer: customerId,            // cust_...
      price: 'price_pro_monthly',      // €29.00 / month
      trialPeriodDays: 14,
      metadata: { source: 'web-signup' },
    },
    { idempotencyKey: `trial-${customerId}` },
  );

  return Response.json({
    subscriptionId: subscription.id,   // sub_...
    trialEnd: subscription.trialEnd,   // unix seconds
  });
}

The first invoice is created but not charged — it sits at 0 due until the trial converts. No payment method is required for a no-card trial.

Collect payment up frontAsk

To auto-convert, attach a payment method before the trial ends. Send the customer through Checkout in setup mode to save a card, then create the subscription with defaultPaymentMethod.

// 1. Save a card via hosted Checkout (no charge during the trial)
const session = await vinr.checkout.sessions.create({
  customer: customerId,
  mode: 'setup',
  returnUrl: 'https://yoursite.com/welcome',
});
// → redirect the customer to session.url

// 2. After they return, start the trial with that method
const subscription = await vinr.subscriptions.create({
  customer: customerId,
  price: 'price_pro_monthly',
  trialPeriodDays: 14,
  defaultPaymentMethod: session.paymentMethod,   // pm_...
});

Some local methods and 3DS-mandated cards can't be charged off-session without prior authorization. When you collect up front, VINR sets up the mandate during the setup session so the conversion charge succeeds. See SCA & off-session.

Trial-end behaviorAsk

Three days before the trial ends, VINR emits subscription.trial_will_end — use it to remind no-card customers to add a method. At trial end, the path depends on whether a method is attached.

The trial converts automatically. VINR finalizes the first invoice and charges it.

const event = vinr.webhooks.verify(
  await req.text(),
  req.headers.get('x-vinr-signature'),
);

switch (event.type) {
  case 'subscription.trial_will_end':
    await emailUpcomingCharge(event.data.customer);   // sub_... ends in 3 days
    break;
  case 'invoice.paid':
    await grantAccess(event.data.subscription);       // converted!
    break;
  case 'invoice.payment_failed':
    await startDunning(event.data.subscription);       // see Failed payments
    break;
}
return new Response('OK', { status: 200 });

With no method, the subscription moves to paused at trial end and stops granting access. Listen for subscription.paused and prompt for payment.

switch (event.type) {
  case 'subscription.trial_will_end':
    await emailAddCardReminder(event.data.customer);
    break;
  case 'subscription.paused':
    await revokeAccess(event.data.id);                 // sub_...
    break;
}

Converting and ending earlyAsk

You can convert a trial immediately (end the trial now and charge) or extend it — handy for support credits or coupon flows.

// Convert now: end the trial and charge the first invoice immediately
await vinr.subscriptions.update('sub_...', { trialEnd: 'now' });

// Extend: push trial end out by 7 days (unix seconds)
await vinr.subscriptions.update('sub_...', {
  trialEnd: Math.floor(Date.now() / 1000) + 7 * 86400,
});

To reactivate a paused no-card subscription, attach a method and set trialEnd: 'now' to charge and resume.

Test itAsk

In the sandbox, set a short trialPeriodDays and use the clock simulation to jump past the trial end, or trigger events manually.

CardConversion result
4242 4242 4242 4242Converts and charges successfully
4000 0000 0000 0002invoice.payment_failed → dunning
4000 0000 0000 32203DS challenge on conversion

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page