Skip to content

Points Expiry

Off by default. When switched on (Settings → Points expiry), a member who has neither earned nor spent for the configured window loses their remaining balance.

The model is inactivity, not per-point age: any earning or spending resets the clock for the whole balance. That is deliberate — expiring each point N days after it was earned needs FIFO lot accounting to know which points a later spend consumed, and gets subtly wrong the moment a reversal lands mid-stack. Inactivity is the version members can predict and you can explain in a sentence.

Members are warned first. A configurable number of days before expiry, the points:expiry_warning app event fires (in-app and email both ON by default — this is the one notification a member is worse off for missing). If they re-engage and later go quiet again, they get a fresh warning.

The preview is the safety net. The settings card shows how many members would lose how many points on the next run, and how many are inside the warning window, before you trust the numbers. Nothing expires until the daily cron runs.

An expiry is an ordinary ledger row of type expire, so:

  • it appears in the member's history with a note explaining why;
  • it does not count as spending (nothing was bought);
  • it does not reduce lifetime earned, so expiry never demotes a level;
  • it can be reversed like any other row if you change your mind.

Front-end: @user(vxp_expires_on) renders the date a member's points are due to expire, and is empty when expiry is off or they hold nothing — so a template can print it unconditionally without showing a stray label.

Built by Code Wattz.