I was testing a Vue 3 + Supabase + Stripe flow locally. The frontend loaded and signup worked, but clicking Upgrade returned a 404 for /api/create-checkout-session.
The endpoint worked on Vercel. The mismatch was the local runtime: vite dev serves the frontend and HMR, but it does not execute files in Vercel's /api directory.
There are two reasonable fixes:
- Run vercel dev and use Vercel's local runtime.
- Run a small Node server for the API handlers, then proxy /api from Vite to that server.
I chose the second option so local testing uses the same handler files as deployment. The request path is:
Browser → Vite :5173 → /api proxy → local Node shim :5175 → same handler
The Vite proxy is small:
server: {
proxy: {
'/api': {
target: 'http://localhost:5175',
changeOrigin: true,
},
},
},
The shim routes known paths to the actual handler modules. It adapts Node request/response objects to the shape those handlers expect, rather than maintaining a second copy of checkout or webhook logic.
Two details took longer to catch than the proxy itself:
- Load .env before importing handlers. The handlers read Stripe and Supabase variables at module load time, so loading .env afterward is too late.
- Preserve the webhook's raw request body. Stripe signature verification uses the original bytes; parsing and re-serializing the body can invalidate an otherwise correct signature.
I run the frontend and API shim separately:
npm run dev
npm run dev:api
Then I test checkout with Stripe test mode and confirm the webhook updates the Supabase subscription row. The live demo is also a sandbox and does not charge a real card.
I wrote up the implementation and tradeoffs in this step-by-step guide.
The Vue 3 + Supabase + Stripe source kit includes the local API shim and notes. It is a separate one-time $29 purchase; the live demo is only a test-mode sandbox.
Disclosure: AI assistance was used to prepare this wording; the project and implementation are mine.
Top comments (0)