Owostack

Set up trials

Offer no-card or card-required trials and understand provider behavior

How to set up trials

Owostack 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

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:

import { plan, metered, boolean } from "owostack";

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

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

const result = await owo.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 Owostack.

Card-required trials

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

const result = await owo.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, Owostack can skip the card-capture checkout and activate the trial directly.

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, Owostack passes the trial period to the provider.

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

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.

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

When a customer is in a trial period:

  1. owo.check() automatically uses the trial limit
  2. owo.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() works normally during the trial:

const access = await owo.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

The exact behavior depends on the provider path:

  • for no-card trials, Owostack runs the trial-end workflow
  • for native-trial providers, the provider handles the first paid charge and Owostack reconciles from provider events
  • for non-native card-required trials, Owostack 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

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

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.

On this page

AI Chat

Owostack docs assistant

Start a new chat below.