What happens if…: trials, plan changes and purchases
Free trials, changing plan, one-off purchases and access: each case, what Gemmein does and what you do.
Free trials
| If… | What happens | What you do |
|---|---|---|
| A customer starts a trial | The plan opens at once and its trial credits are granted once. g.subscriptions.mine() answers trialing with trialEndsAt | Unlock on plan, as for any subscriber |
| The trial ends and the card pays | The status becomes active, and the plan's credits for the first paid period are granted | Nothing |
The trial ends and the card is declined, with onPaymentFailure keep | The customer keeps the plan while Stripe retries the card. If Stripe gives up, they move to your default plan | Set the retries in your Stripe subscription settings |
The trial ends and the card is declined, with onPaymentFailure end | The customer moves to your default plan at once. If a retry succeeds later, the plan opens again | Nothing |
| The trial ends with no card (card optional) | Stripe cancels the subscription and the customer moves to your default plan | Send them to g.subscriptions.manage() to add a card before the trial ends |
| The customer cancels during the trial | They keep the plan until the trial ends, are not charged, then move to your default plan. mine() answers endsAt | Nothing |
| The same customer asks for another trial | Checkout sends them to the plan's paid link. One trial per customer per app, and none for anyone who has paid for a plan. A +tag or a Gmail dot is the same customer | Nothing |
| Someone uses many addresses on a catch-all domain | Each address is a separate customer, so each can start a trial | Keep the card required (the default) for plans where that matters |
| A trialing customer switches plan | The trial ends, and the new plan's first-period credits are granted when the switch is paid | Nothing |
| A customer deletes their account and signs up again | They are a new customer, but their trial stays used | Nothing |
| Someone opens the trial link without your app, or starts two trials in two tabs | Only one trial Gemmein offered opens a plan. Any other grants nothing, and Errors names it | Cancel that subscription in Stripe |
| You change or remove a plan's trial | New customers get the new offer. Trials already running keep theirs | Nothing |
| Development has given 25 trials today | Checkout hands out the paid link until the day rolls on. Live has no cap | Nothing |
Changing plan
| If… | What happens | What you do |
|---|---|---|
Your app calls g.subscriptions.manage() for someone who has never paid for a plan | It answers no_subscription; there is nothing to manage | Show the plans instead |
Your app calls g.subscriptions.manage() and the app sells no plans | It answers no_plans. A plan removed while members still pay keeps their portal open | Nothing |
| The portal can't open: Stripe isn't connected here, or the key lacks Customer portal: Write | g.subscriptions.manage() answers portal_unavailable, with a message safe to show the member. In Development, ownerDetail says what to fix on Payments | Connect Stripe, or add the row to the key in Stripe |
| Gemmein can't read the app's payments for a moment | g.subscriptions.manage() answers portal_unavailable and nothing changes | Let them try again |
| Stripe can't be reached when the portal opens | g.subscriptions.manage() answers portal_unavailable and nothing changes. Nothing in your app needs fixing | Let them try again shortly |
| A member opens the portal more than 10 times in 10 minutes | It answers portal_rate_limited. Development also allows an app 100 opens an hour | Let them try again in a few minutes |
A subscriber calls checkout for another plan or the same one | It answers already_subscribed with the portal link, whether their subscription is active, trialing, past due, unpaid, paused or incomplete. No second subscription is started | Send them to the url it returns |
| The same person opens two checkouts for a plan at once | The second answers checkout_in_progress for a few seconds. After 24 hours a checkout link only pays for the person it was made for | Nothing |
| Two subscriptions for one person go live anyway | Errors shows "Duplicate subscription — cancel one in Stripe". Gemmein can't cancel in Stripe | Cancel one in Stripe |
| A subscriber moves to a plan with more credits | The new plan opens at once. Its extra credits arrive when the upgrade is paid. Each prorated line is priced on its own: the new plan's per-period credits × the share of the period the line covers, minus the same for the old plan, each line by its own discounts (tax excluded). A line in another currency than its plan grants nothing. A 99% coupon gives 1% of the credits, and several changes on one invoice each count once. If your portal bills prorations later, they come with that invoice | Nothing |
| A subscriber moves to a plan with fewer credits, or the upgrade is refunded | Credits are taken back at the same rate for the money returned, first from what the upgrade granted. A credit pack's own line is never touched, and the ledger records it as a plan change | Nothing |
| A downgrade returns money for credits you already used | Your balance goes below zero until your next renewal or purchase. It can't be spent; the next renewal or pack pays it down first | Nothing |
| A subscriber moves up, spends, and moves back down, again and again | The credits gained match the money kept. What they spent ahead stays a debt | Nothing |
| A subscriber switches during a trial | The trial ends and the new plan opens. A switch that charges nothing grants no extra credits | Nothing |
| A renewal and a plan change arrive out of order | The renewal grants the credits of the plan on its own invoice's subscription line | Nothing |
One-off purchases
Signed-out buyers, the purchase email and deleted accounts have their own sections: Buying signed out, The purchase email and A deleted account.
| If… | What happens | What you do |
|---|---|---|
| A buyer pays by bank debit | The product is granted once the payment clears. A failed payment grants nothing, and Logs says so once | Nothing |
| A checkout never clears | It is closed after 30 days. A payment that still arrives is fulfilled | Nothing |
| A purchase is refunded in full | The product's access and credits are taken back, the purchase reads refunded, and g.files.link refuses its file from the next request | Nothing |
| The buyer downloaded the file before a full refund | No new download link is issued. A copy already on their device stays with them (see Limits) | Nothing |
| A purchase is refunded in part | Access, credits and the file stay. The purchase reads part_refunded | To take access back, revoke it on the person's page |
| A credit pack is refunded in full after some credits were spent | What is left of that purchase's credits is taken back, never below zero | Nothing |
| A buyer who also subscribes is refunded for a product | Only what that purchase opened closes. The subscription's access stays | Nothing |
| A subscriber who bought products cancels | Products bought outright stay | Nothing |
| A refund arrives before its payment | It is applied when the payment lands: a full refund grants nothing, and a partial one grants the product and records the refund | Nothing |
| Stripe sends the same payment twice | The product and its credits are granted once | Nothing |
| The 14-day waiver is turned on | Each one-off product (a file, a link, or access alone) gets a new Payment Link whose checkout requires the box; the old link goes off. Plans and credit packs are unchanged | Nothing |
The 14-day waiver is turned on without termsUrl | Refused with consent_terms_url_required. A link that isn't https, carries a username or password, or is over 500 characters is refused with invalid_consent. Nothing changes | Add your Terms of Service link as termsUrl |
termsUrl changes while the waiver is on | Each such product gets a new Payment Link whose box links the new terms; the old links go off | Nothing |
| A save would make more than 10 new Payment Links in a day in Development, or 50 in Live, for things already on sale | Refused with development_capped (Live: links_capped). Nothing changes. A new price makes one link; the 14-day waiver turned on or off, or a new termsUrl, makes one per product it covers; promote counts the same. A product's first link never counts | Try again the next day (UTC) |
| You change the 14-day waiver on the Payments page after your AI set it | The next npx gemmein sync shows a conflict and keeps your setting | Run npx gemmein sync --overwrite to take the file's |
| The 14-day waiver is on when you go live or promote | The Go live page notes that Live needs a Terms of Service link set in your Stripe live account | Set it in Stripe live mode first |
| A buyer pays on a link replaced days ago | The payment still resolves to its product | Nothing |
| A domain is verified, or the return path changes, while the 14-day waiver is on | Each Payment Link is pointed at the new return in place. The box stays, no link is made again, and nothing counts against the daily cap | Nothing |
| The 14-day waiver is turned on and Stripe has no Terms of Service link | Refused with stripe_terms_url_missing. Nothing changes | Add the link in Stripe under Settings → Business → Public details, then turn it on again |
| A buyer pays with the 14-day waiver on | Every Logs row of the purchase records consent: accepted, with the words the buyer ticked | Nothing |
| A buyer opened checkout on the old link before the waiver was turned on | They can still finish paying, without the box. The purchase is fulfilled, and its Logs rows carry no consent | Nothing |
| The 14-day waiver is turned off | The products get new links without the box. Purchases already made keep their record | Nothing |
A relay refunds a product with refund_product | Exactly what that purchase added is taken back. A purchase made through Stripe is refunded only in Stripe | Refund Stripe purchases in Stripe |
Access
| If… | What happens | What you do |
|---|---|---|
| A signed-out visitor opens a locked collection | They are told to sign in, never which plan or product unlocks it | Nothing |
| A signed-in person without the plan or product opens it | Refused until they hold one of the plans or products in Unlocked by | Send them to checkout |
| You grant access by hand with an end date | It opens at once and closes on its own at that date. A date already past is refused | Nothing |
| Access was granted in Development | It never opens anything in Live | Grant it again in Live |
| Your dashboard or a secret key reads a locked collection | It is not refused: the lock applies to customers | Nothing |
Was this page helpful?
Thanks for telling us.
Thanks for telling us.
Last updated