How do I run a launch price that expires on a date?
Set STRIPE_PRICE_KIT_LAUNCH and KIT_LAUNCH_PRICE_ENDS_AT. The app decides which price id to use from the date, and the same decision drives the number shown on the pricing page and the structured data. One source, so the price a customer is charged can never disagree with the price they were shown.
The two variables
| Variable | What it holds |
|---|---|
STRIPE_PRICE_KIT_LAUNCH |
The discounted price id, used while the window is open. |
KIT_LAUNCH_PRICE_ENDS_AT |
An ISO date. After it, the standard price id is used. |
STRIPE_PRICE_KIT is the standard price and is what the app falls back to.
bin/rails runner 'puts KitPrice.current.cents'
That prints the price the app will actually charge right now, which is the number worth checking before you announce anything.
Why it is derived rather than written twice
The obvious version of this feature is a price id in the config and a number typed into the pricing page. They drift the first time someone edits one and not the other, and the failure is a customer charged one amount after being shown another, which is a refund and an apology at minimum.
Here the displayed price, the checkout price and the offers.price in the page's structured data all
read the same object. A spec asserts the structured data matches, so the three cannot separate
without failing bin/check.
Expiry is evaluated per request, not cached at boot
The window closes on its own at the date you set. There is no deploy to remember and no job to schedule. That also means moving the date is a configuration change and a restart, not a release.
Do not delete the old price in Stripe
Archive it instead. Existing customers on a recurring launch price keep that price, and deleting it breaks their renewals. Archiving hides it from new checkouts and leaves the existing ones alone.
Test the boundary
Set KIT_LAUNCH_PRICE_ENDS_AT to yesterday in development and reload the pricing page. It should
show the standard price, and checkout should use the standard id. Then set it to tomorrow and confirm
both switch back. Two minutes, and it is the only way to know the boundary works before the night it
matters.