Edit in StackBlitz next generation editor ⚡️
All backend endpoints (/api/widgets, /api/billing, /api/vapi-assistants, /api/vapi-provision,
/api/stripe-checkout, ...) are Netlify Functions in netlify/functions/. netlify.toml redirects
/api/* to /.netlify/functions/:splat, but that redirect only exists inside Netlify's own dev proxy
and in production — it is not something Vite knows about.
That means:
npx netlify dev— the intended way to run this app locally. It starts Vite (npm run dev) and a local Functions server together, and applies thenetlify.tomlredirects in front of both, so/api/*reaches a real function. Requires the Netlify CLI (npm i -g netlify-clior usenpx).npm run devalone — runs only the Vite dev server, with no functions server and no redirect. A request to/api/widgetsfalls through to Vite's SPA fallback and gets backindex.htmlinstead of JSON, which used to surface asUnexpected token '<', "<!doctype "... is not valid JSON.vite.config.tsnow proxies/api/*to a local Netlify Functions server (defaulthttp://localhost:8888, the same portnetlify devexposes) and rewrites it to/.netlify/functions/*, sonpm run devworks too as long as a functions server is running on that port (e.g. anetlify devprocess, ornetlify functions:serve). Override the target withVITE_FUNCTIONS_PROXY_TARGETif it runs elsewhere. This proxy only affects the Vite dev server — it has no effect onnetlify dev(whose own proxy already handles/api/*before requests reach Vite) or onnpm run build/vite preview.
Either way, every /api call in the app goes through src/lib/fetchJson.ts (fetchJson /
authenticatedFetchJson), which checks the response status and content-type before parsing JSON. If a
request can't reach a real API handler — backend down, wrong port, no functions server — it throws a
typed ApiError with a clear message ("Couldn't reach the API — is the backend running?") instead of a
raw JSON-parsing exception.