billing 14 Sep 2026 · 4 min read

A Refund Should Take Back Access Too

We ran a refund on our own account to check that the ledger reversed correctly. It did. Then someone read the rest of the account state, which is where the real finding was: the plan was still active, and still active un…

ToRun Team ToRun Team

We ran a refund on our own account to check that the ledger reversed correctly. It did. Then someone read the rest of the account state, which is where the real finding was: the plan was still active, and still active until the middle of next month.

Money back, access kept. Repeatable every month by anyone willing to click Refund. It was not found by a test, because no test asked the question.

Ending the span the payment bought

On a full refund, the period that payment opened now ends immediately, and a lifecycle event records why.

Immediately — but not to nothing. If you were on one plan, upgraded to a more expensive one, and the upgrade payment is refunded, you go back to the plan you were on, not to the free tier. You paid for that month separately and it was not refunded. Taking it as well would be the platform helping itself to something the customer still owns. Only someone with no earlier plan still running falls back to free.

Entitlement has two halves

The first version of this fix ended the subscription row and stopped. But what you are allowed to do hangs off two things: the row the budget reads, and a role that was granted when the payment succeeded. Every other path that ends a subscription drops that role explicitly. This one did not, so a refunded account would have been cancelled on paper while still holding the paid tier's permissions.

The role is dropped too now, and it lands on the restored plan's tier rather than on a blanket free — the same reasoning as the restore itself.

Telling the provider

The account page said Free Tier. The payment provider's dashboard said Active, next billing next month. The refund had ended things on our side and never told the other side, so the customer was queued to be charged again for a plan they had been refunded and could no longer use — and had no way to stop it from our screens, because cancelling requires an active subscription and we had just cancelled theirs.

A refund now stops auto-renew at the provider that issued the payment. Not an immediate termination: auto-renew stops, so no further money moves, and the provider's own record winds down on its own schedule instead of being torn up underneath a refund it has just processed.

With one exception, which the owner spotted before it shipped. If the plan you were restored to rides the same provider subscription, cancelling it would leave you showing a plan that never renews and never charges — the exact mirror of the bug this exists to fix, and just as quiet. That case is now named explicitly and left alone.

Only the payment that opened the period may end it

An upgrade mid-month on this provider charges a small prorated difference against the existing row. Refunding that small charge would have found one subscription, cancelled the whole thing, looked for an earlier plan, found none, and dropped the customer to free — over a partial-month adjustment. Now only the payment that opened the current period is allowed to end it. Anything later is a money question, and the ledger has already answered it.

All four rails, not just the live one

Three of the four payment processors we support have nobody on them today. The revoke could have been fixed only on the live one, and it very nearly was. The objection that changed it: the day one of the others is switched back on, the hole comes back, and by then nobody will remember it was ever there.

This repository has shipped the same class of forgotten trap six times. The revocation now lives behind one contract that all four processors call in a single line, so a future maintainer switching one of them back on gets it without needing to have read any of this.