Trials

Trials are another layer on the same checkout session, the way Automatic Tax and Promotion Codes are. An eligible user subscribes without being charged, Stripe creates the subscription as trialing, and the first real invoice bills when the trial ends. The card is still collected at signup, it just isn't charged, so there's something to bill at the end without anyone on the page.

The mode is the switch

There's no separate flag. SUBSCRIPTION_MODE=trial turns the layer on, and SUBSCRIPTION_TRIAL_DAYS sets the length. In any other mode no session carries a trial and every signup is charged on confirm. The same mode also gates access and stamps a trial at registration, which is covered in Plans & Subscriptions.

Which plan

A trial only applies to one plan, the lowest tier that isn't free, provided it's active and public. It's worked out from the tier rather than a slug or a flag on the table, so there's nothing to keep in line when plans change. A plan nobody can see is skipped, since it would leave every listed plan without a trial.

Every other plan is charged on confirm. That includes a user who still has days left over from registration, who doesn't carry them onto a different plan, because otherwise the restriction could be sidestepped by registering without a card.

The plan list marks the trial plan with is_trial, which is only ever true in trial mode, so the client can label the plan card without checking the settings endpoint as well. It says which plan the trial applies to and nothing about the user. Whether a particular user gets one is decided by the API when the session is created, and the client learns about it from the session total.

Eligibility and the trial end

The API decides and the client never asks. When the session is created, resolveTrialEnd() works out a date and the session is sent with subscription_data.trial_end. It's a timestamp rather than a number of days because a user carrying a partial trial keeps whatever is left of it, and a whole number of days can't say that.

Where the date comes from depends on SUBSCRIPTION_REQUIRE_CARD. With it off, which is the default, the trial clock was stamped at registration, so a user who subscribes mid-trial carries the days they have left. The stamp never restarts, and once it has passed they get nothing, which is what stops a second trial. With it on, nothing is stamped at registration. A first-time subscriber gets a fresh window of SUBSCRIPTION_TRIAL_DAYS at subscribe, and anyone who has subscribed before gets none.

Stripe only accepts a trial end at least 48 hours in the future. A user with less than that left would see the session create fail with the provider error, so the last two days of a registration trial are a known gap.

At signup

Nothing is charged on the confirm. The invoice is $0 and the subscription lands at trialing with the trial end Stripe was given. The sync writes it like any other signup, trialing counts as live for access and for the plan, and the trial end goes onto the local subscription.

Because nothing was paid, Stripe has no payment to make the card the default off the back of, so the sync does it by hand. It points both the customer and the subscription at the card, using the one the subscription carries if there is one and otherwise the newest card on the customer, which is the one the user just entered. It goes through the same service as replacing a card, so any other cards on the customer are detached along the way.

While trialing

Cancelling runs access to the end of the trial with nothing to refund. Stripe puts the cancel date on the trial end, so the cancel service reads it the same way it reads any other term. Changing plan is refused with on_trial, outright for now.

The profile carries the trial end as trial.ends_at, which is what the client reads for the cancel wording. A paid term has no end date on the local subscription until it's actually cancelled, so a trial is the only case where there's one to show beforehand.

When the trial ends

The first real invoice bills the card on file. If that charge fails it's an ordinary failed renewal and goes through the same handling as any other. A promotion code applied to a trial discounts that first charge, which is covered in Promotion Codes.

© Websanova 2026 About Privacy