# Set up trials (https://docs.billwave.example/subscriptions/trials)

How to set up trials [#how-to-set-up-trials]

Billwave supports two trial shapes:

* **No-card trials**: `trialDays > 0` and `trialCardRequired = false`
* **Card-required trials**: `trialDays > 0` and `trialCardRequired = true`

Both provision the plan’s entitlements during the trial period.

Create a plan with a trial [#create-a-plan-with-a-trial]

In the dashboard, set **Trial Days** when creating the plan. If you want card
collection up front, also enable **Require card for trial**.

In code:

```ts
import { plan, metered, boolean } from "@digvijay-x1/billwave";

const apiCalls = metered("api-calls");
const analytics = boolean("analytics");

plan("pro", {
  name: "Pro",
  price: 2000,
  currency: "USD",
  interval: "monthly",
  trialDays: 14,
  features: [apiCalls.limit(10000), analytics.on()],
});
```

No-card trials [#no-card-trials]

If `trialCardRequired` is false, `attach()` creates the trial directly.

```ts
const result = await billwave.attach({
  customer: "user_123",
  product: "pro",
});

console.log(result.trial); // true
console.log(result.checkoutUrl); // undefined
```

This path creates a `trialing` subscription immediately and schedules trial-end
handling in Billwave.

Card-required trials [#card-required-trials]

If `trialCardRequired` is true, `attach()` may return a checkout URL so the card
can be collected before the trial starts.

```ts
const result = await billwave.attach({
  customer: "user_123",
  product: "pro",
  customerData: { email: "user@example.com" },
});

if (result.checkoutUrl) {
  return Response.redirect(result.checkoutUrl);
}
```

If the customer already has a payment method on file, Billwave can skip the
card-capture checkout and activate the trial directly.

Provider behavior [#provider-behavior]

Provider handling depends on whether the adapter supports native trials.

* **Stripe**: native trial support
* **Dodo Payments**: native trial support
* **Polar**: native trial support
* **Paystack**: no native trial support

For native-trial providers, Billwave passes the trial period to the provider.

For Paystack, Billwave uses an auth/capture-style card verification flow when a
card is required, then manages the trial lifecycle itself.

Trial-specific limits [#trial-specific-limits]

You can set different usage limits for metered features during the trial period. This is useful for giving customers a taste of your product without providing full access.

```ts
plan("pro", {
  name: "Pro",
  price: 2000,
  currency: "USD",
  interval: "monthly",
  trialDays: 14,
  features: [
    metered("api-calls").limit(10000, 
      reset:"monthly",
      trialLimit:5000
    )
    metered("ai-tokens").limit(50000,
      reset:"monthly"
      trialLimit:10000
    ),
  ],
});
```

In this example:

* During the 14-day trial: customers get 1,000 API calls and 5,000 AI tokens
* After trial converts: customers get 10,000 API calls and 50,000 AI tokens

If you don't set a `trialLimit`, the regular `limit` applies during both trial and active periods.

How it works [#how-it-works]

When a customer is in a trial period:

1. `billwave.check()` automatically uses the trial limit
2. `billwave.track()` counts against the trial limit
3. The dashboard shows a "Trial" badge on the customer's entitlements

When the trial ends:

1. The trial-end workflow resets usage meters to use regular limits
2. The customer's next `check()` call sees the full limit
3. Any remaining trial balance does not roll over

Check trial status [#check-trial-status]

`check()` works normally during the trial:

```ts
const access = await billwave.check({
  customer: "user_123",
  feature: "api-calls",
});

console.log(access.allowed); // true
console.log(access.balance); // 1000 (during trial)
console.log(access.details?.trial); // true
console.log(access.details?.trialEndsAt); // "2026-03-20T12:00:00Z"
```

The subscription status remains `trialing` until the trial ends.

What happens when the trial ends [#what-happens-when-the-trial-ends]

The exact behavior depends on the provider path:

* for no-card trials, Billwave runs the trial-end workflow
* for native-trial providers, the provider handles the first paid charge and
  Billwave reconciles from provider events
* for non-native card-required trials, Billwave manages the trial lifecycle

The normal lifecycle is:

1. A billing workflow fires at the trial end date
2. The customer's card is charged the full plan price
3. On successful payment, the subscription moves to `"active"`
4. If payment fails, the subscription moves to `"past_due"`

Trial + free plan [#trial--free-plan]

A common pattern is a free tier in the main plan group plus a trial on the paid
plan:

```ts
plan("free", {
  name: "Free",
  price: 0,
  currency: "USD",
  interval: "monthly",
  planGroup: "main",
  features: [apiCalls.limit(100), analytics.off()],
});

plan("pro", {
  name: "Pro",
  price: 2000,
  currency: "USD",
  interval: "monthly",
  planGroup: "main",
  trialDays: 14,
  features: [apiCalls.limit(10000), analytics.on()],
});
```

When a customer on `free` attaches to `pro`, they enter the trial for the paid
plan in the same group.

Related guides [#related-guides]

* [Plans & products](/pricing/plans)
* [Plan switching](/subscriptions/plan-switching)
* [Pricing models](/pricing/pricing-models)