Toolaby

Subscriptions

The life of a buyer's subscription, from checkout to its end, and what your extension, your dashboard and your server see at each step.

A subscription is a plan Stripe bills every month or year, on your Stripe account. The buyer signs in before they subscribe, so a subscription always belongs to an account. Toolaby follows it from Stripe's events: it unlocks the tool while Stripe's status is active or trialing, and in no other status.

This page follows one subscription from checkout to its end. At each step it says what gate(), getUser() and the Toolaby popup answer, what the tool's Customers page shows, and which webhook events are sent.

Statuses

StatusWhenUnlocksCustomers shows
trialingIn a free trial taken at checkoutyesTrial until 12 Oct 2026
activePaid for the current periodyesRenews 12 Nov 2026, or Ends 12 Nov 2026 once set to end
past_dueA charge failed, and Stripe is retrying itnoPast due
unpaidStripe stopped retrying and kept the subscriptionnoUnpaid
canceledIt has endednoEnded 12 Nov 2026

A subscription can also be Held by the plan: a pass beyond the Hobby plan's 100, which unlocks nothing until there is room. See Plans.

What the extension sees

getUser() and gate() answer from the device. The device hears of a change when it next asks Toolaby: it asks for a fresh token every 15 minutes, and the Toolaby popup asks when it opens. On Live, the popup asks once its last answer is five minutes old.

trialing, activepast_due, unpaid, canceled
gate(){ allowed: true, isPremium: true, unlimited: true }, with the plan's featuresWhat the Free plan gives. With Nothing free: { allowed: false, reason: 'paid' }
user.paidtruefalse
user.via'subscription'null
user.planThe plan heldnull
user.paidAtThe current period's startnull
user.subscription{ status, periodEnd, cancelAtPeriodEnd, cancelAt }The same, with Stripe's status

user.subscription is there whatever the status, so your popup can say why the tool is locked. periodEnd is when the current period ends: in a trial, the trial's end. cancelAtPeriodEnd is true once the subscription is set to end, and cancelAt says when. user.trial describes a trial started without a card from your website, not one taken at checkout. See User.

1. Checkout

The buyer picks the plan on the checkout page and pays on Stripe's page. A plan with a free trial takes the card and charges nothing until the trial ends. Each inbox gets one trial per tool: see Pricing.

When Stripe has made the subscription:

  • It is trialing with a trial, active without one.
  • Toolaby sends purchase.completed, with kind: 'subscription', and subscription.started. Both carry status, period_end and user_id; purchase.completed has no email or amount for a subscription.
  • The members who chose sale notifications get an email. See Notifications.
  • The after-purchase page signs the extension in to the buyer's account, and the device unlocks. onPaid fires in the background.
  • The buyer appears under Customers.

2. The trial

A trialing subscription unlocks the tool as a paid one does. Stripe's current period is the trial: period_end, user.subscription.periodEnd and the date under Customers are the trial's end.

The Toolaby popup opens your popup. With no popup of yours behind it, it shows the plan and Renews 12 Oct · €3 / month: the date of the first charge.

When the trial ends, Stripe charges the card. Paid, the subscription is active. Refused, it is past_due (step 4). Neither sends an event.

3. Renewal

Each period, Stripe charges the card. Paid, the subscription stays active, and user.subscription.periodEnd, user.paidAt and the Renews date under Customers move on to the new period. No event is sent.

On the Hobby plan each charge carries Toolaby's fee. See Money.

4. A payment fails

A charge Stripe cannot make, such as a declined or expired card, leaves the subscription past_due while Stripe retries it. past_due unlocks nothing:

  • gate() answers as the Free plan does. With Nothing free, it refuses with paid.
  • getUser() answers paid: false, via: null and subscription.status: 'past_due'.
  • Where the Free plan does not let the device through, the Toolaby popup says Payment failed — update your card, with the way to the account page. Where it does, as on Everything free, it opens your popup.
  • Customers shows Past due, under Needs attention.
  • No event is sent.

A team subscription's seats are paused while it is past due. See Seats.

When a later attempt pays the invoice, the subscription is active again, and the device unlocks at its next check. No event is sent.

When Stripe's retries run out, Stripe cancels the subscription, marks it unpaid or leaves it past_due, as your Stripe account's settings for failed payments say. Cancelled, it has ended (step 6). unpaid unlocks nothing, shows Unpaid under Customers, and sends no event.

5. Set to end

The buyer cancels from their account page, in Stripe's portal. Or you select Cancel on the customer's page, At the end of the period. The subscription stays active, and unlocks until the period ends.

  • getUser() answers subscription.cancelAtPeriodEnd: true, and cancelAt, the day it ends.
  • The Toolaby popup, with no popup of yours behind it, shows Ends 12 Nov · €3 / month.
  • Customers shows Ends 12 Nov 2026, under Needs attention. In a trial it still shows Trial until.
  • Toolaby sends subscription.cancelled, with immediately: false and ends_at, as soon as the subscription is set to end: from Cancel, or from the portal, which records it as a cancel_at date.

subscription.cancelled is sent once a day at most: set to end, kept, and set to end again on the same day (UTC) is one event.

Keep, on the customer's page, undoes the cancellation before the period ends: the subscription renews as before. No event is sent.

6. Ended

The subscription is canceled at the end of the period it was set to end at, after Cancel with Now, or when Stripe cancels it after its retries.

  • gate() answers as the Free plan does. getUser() answers paid: false, via: null and subscription.status: 'canceled'.
  • The Toolaby popup answers as for any device on the Free plan.
  • Customers shows Ended 12 Nov 2026.
  • Toolaby sends subscription.cancelled, with immediately: true; ends_at is when it ended.
  • A team subscription's seats are revoked. See Seats.

7. A refund

A subscription's payment is refunded on the payment in your Stripe Dashboard: Refund on the customer's page is for licences. On Test, the Stripe account Toolaby makes has no Stripe Dashboard, so a subscription's payment is not refunded there.

A refund leaves the subscription as it is. It runs on and unlocks, and no event is sent. To end it as well, cancel it (step 5 or 6).

A refund of the payment for the current period makes that period a pass: its charges no longer pay for it.

8. A dispute

A buyer who disputes a subscription's payment with their bank leaves the subscription as it is: it runs on and unlocks.

  • Toolaby sends payment.disputed when the dispute opens, with licence empty and the invoice's address in email.
  • It sends dispute.closed when the dispute is won or lost.
  • The members who chose dispute notifications get an email, with the deadline to respond.

If the disputed payment paid for the current period, that period is a pass while the dispute is open, and stays one if the dispute is lost.

Events

MomentEvent
Subscribed, with or without a trialpurchase.completed and subscription.started
A trial ends, a renewal, a payment fails, a failed payment is paidnone
Set to end at the period's endsubscription.cancelled, immediately: false
Set to end, then keptnone
Endedsubscription.cancelled, immediately: true
A plan switched in Stripe's portalnone
A payment refundednone
A payment disputedpayment.disputed, then dispute.closed when won or lost

A server that needs to know who is paid, past due included, asks the API: Retrieve a customer answers entitled and the subscription's status, whatever it is. See Sync customers.

See also

On this page