Test mode: break your pricing in the sandbox, not on your customers
You changed the free tier from 10 to 25 generations and somehow locked out every Pro user for an hour. Nobody tested it, because testing it meant tracking fake events into production analytics. There is a mode for this.
Why pricing logic goes untested
Nobody ships a payment flow without testing it, yet metering changes go out blind constantly. The reason is friction: testing a limit means generating events, and generating events into production pollutes the analytics you make decisions with, skews the very counters you are trying to verify, and - if you meter your own usage - costs real quota. So devs test pricing changes by squinting at the diff. The fix is the same one Stripe taught everyone a decade ago: a test mode that is a real, full-fidelity environment, not a mock.
The key is the switch
Every Vevee app has four keys: pk_live / sk_live and pk_test / sk_test. The prefix is the entire mode mechanism - same SDK, same endpoints, same plans and limit groups, but test keys read and write an isolated set of runtime tables. End-user state (events, counters, subscriptions, reservations) is fully partitioned; configuration (apps, plans, match rules) is shared. That split is exactly what you want for pricing tests: you exercise the real plan you are about to ship, against throwaway users.
// The only line that differs between prod and test
const vevee = createClient({
apiKey: process.env.NODE_ENV === 'production'
? process.env.VEVEE_SECRET_KEY! // sk_live_...
: process.env.VEVEE_TEST_SECRET_KEY!, // sk_test_...
});The pre-ship ritual, scripted
Because test mode is just the SDK with a different key, a pricing change gets an integration test like any other code. Subscribe a fake user to the changed plan, walk them to the limit, assert the wall appears exactly at the new number, assert the premium sub-cap still binds. Run it in CI if you like - test events are isolated, so the suite is rerunnable. This is the test you could never write against production.
// pricing-change.test.ts - runs against sk_test
const u = 'test_user_' + Date.now();
await vevee.upsertSubscription({ userId: u, planId: 'free' });
for (let i = 0; i < 25; i++) {
expect(await vevee.can(u, 'image_generation')).toBe(true);
await vevee.track(u, 'image_generation');
}
// the 26th must hit the new wall
expect(await vevee.can(u, 'image_generation')).toBe(false);The dashboard follows you
Test mode is not headless. Flip the workspace toggle and the entire dashboard - usage charts, event feeds, subscription lists - reads the sandbox universe, with a yellow TEST MODE banner so you always know which reality you are looking at. This is how you demo the product to a stakeholder with realistic-looking data, debug a customer-reported limit issue by reproducing it safely, or check that your seeded staging environment looks right, all without a single fake row in production.
The fine print that keeps it honest
Two boundaries worth knowing. Test data older than 30 days is hard-deleted by a daily sweep - the sandbox is a workbench, not an archive, so never point anything you care about at a test key. And test-mode operations count toward your workspace’s plan cap just like live ones; the sandbox is isolated for data, not unmetered, so routing production traffic through a test key buys you nothing except missing analytics. Use live keys for users, test keys for everything else - staging, CI, demos, and every pricing change before it meets a customer.
Keep reading
The race condition in "if (usage < limit)" that is costing your AI app money
A user at nine of ten images opens six tabs and clicks generate in all of them. Every tab passes your limit check, every tab gets an image, and you pay for all six. The bug is one read-then-write - and your unit tests will never catch it.
MeteringHow to build a credits system for your AI app (ledger design, rollover, refunds)
A user emails: "I had 40 credits this morning and now I have 12, and I only made one image." If your balance is a column you mutated, you cannot answer that email. Here is the ledger design that can.