How Do I Handle Refunds and Returns?
Issue full or partial Stripe refunds directly from the order screen, understand return policy settings, and see how the refund webhook keeps your inventory and access controls in sync.
Refunds are never fun, but handling them cleanly builds trust faster than almost anything else you can do as a store owner. VeloCMS lets you issue Stripe refunds directly from the order detail screen — no logging into Stripe separately, no risk of mismatching the amount. Everything stays in sync automatically.
Issuing a full refund
Go to Admin → Orders and click any order row to open the detail view. At the top right you'll see a 'Refund' button. Click it and a panel slides out showing the order total pre-filled — just confirm and hit 'Process refund.' VeloCMS calls the Stripe API with the full charge amount, marks the order status as 'refunded,' and fires the customer notification email through Resend. The whole round-trip takes two or three seconds.
For digital product orders, a full refund automatically revokes all download links associated with that order. Any click on a revoked link returns a 410 Gone response. This happens synchronously with the Stripe call — there's no window where someone could click through between the refund and the revocation.
Partial refunds
Same refund panel, but instead of accepting the pre-filled total, you type a lower amount. Useful for shipping disputes, minor product defects where you're offering a goodwill discount rather than a full return, or when you've negotiated a compromise with the customer. The order status stays 'completed' (since it wasn't fully refunded), and a refund record appears in the order's timeline showing the partial amount, timestamp, and reason. You can issue multiple partial refunds on a single order as long as the cumulative total doesn't exceed the original charge — Stripe enforces this ceiling.
Refunds debit your Stripe balance directly. If your balance is low relative to the refund amount, Stripe may delay processing until your next payout cycle tops it up. Check your Stripe Dashboard → Balance before issuing unusually large refunds.
The refund webhook
Behind the scenes, VeloCMS listens to the Stripe 'charge.refunded' event at the /api/stripe/webhook endpoint. This means refunds you initiate outside VeloCMS — say, directly in the Stripe Dashboard for some reason — also get picked up automatically. The webhook handler updates the order status, creates the refund record, and handles access revocation for digital orders. It's idempotent: if the same event arrives twice (Stripe does retry on transient failures), the second run is a no-op.
Return policies
VeloCMS doesn't enforce a return window automatically — that would be too opinionated for the variety of things people sell. Instead, go to Admin → Settings → Store Policies and paste or write your return policy text. It renders on a /policies/returns page and is linked from the checkout footer automatically. Whether you offer 30-day no-questions-asked returns or a strict no-refund policy for custom work is entirely up to you; the platform just makes sure the policy text is discoverable by customers.
Physical returns and inventory
VeloCMS doesn't have a built-in returns management workflow for physical products — there's no 'mark as returned' button that automatically restocks inventory. The recommended flow: issue the Stripe refund from the order screen (which handles the money side), then manually adjust the inventory quantity on the relevant product variant once the item physically lands back with you. It's a two-step process, but it keeps inventory numbers accurate rather than restocking speculatively when the refund is issued.