Endpoint mapping contract
Pulse Routing
Pulse routing defines how source files map to same-origin /api routes and how those routes are exposed to runtime callers, embeds, and automation surfaces.
Route contract reference for mapping Pulse files to API endpoints.
Implementation focus
Use this page when creating or refactoring server routes so call paths and deployment behavior remain predictable.
Expected outcomes
- Map source layout to stable /api route contracts.
- Avoid route collisions during iterative releases.
- Preserve clear ownership across handler files and surfaces.
The src/server/ (and server/) Convention
Vibecodr uses a file-based routing convention. TypeScript and JavaScript files inside src/server/ (preferred) or server/ publish as API endpoints when the project ships as a Pulse or Combo.
Mental model: src/server/ tells Vibecodr what should run as backend code, while /api/* is the URL surface people and browsers actually call.
The same convention applies to GitHub and ZIP imports. Framework apps like Vite + Svelte can keep their frontend source and add src/server/ endpoints. Frontend previews in Studio; server files deploy as /api/* routes when you publish. Built-only archives such as dist/ do not contain enough source to create backend routes.
How to deploy a Pulse (serverless compute)
- Add backend function files to
src/server/(preferred) orserver/. - Verify file-to-route mapping (
src/server/foo.ts -> /api/foo). - Publish from Studio; Vibecodr bundles and deploys the Pulse runtime automatically.
- Blueprint starters open in Studio as Pulse source with setup tasks, not as browser preview apps. Finish the checklist, publish, then test the deployed endpoint.
- PulseDescriptor normalizes Pulse setup metadata internally; simple one-file handlers remain simple, and setup UI, examples, local replay, API/OpenAPI, MCP, CLI, and deployment validation read the normalized descriptor projection.
- For standalone automations and webhooks, use the Pulse Operating Center or go straight to Pulse creation.
Vibes (Browser Code)
Files outside src/server/ run in the browser.
src/App.tsx, index.html
Pulses (Server Code)
Files inside src/server/ (or server/) become API endpoints.
src/server/weather.ts -> /api/weather
File Path to Route Mapping
Your file path determines your API route. Here's how the transformation works:
File Path
API Route
Notes
src/server/weather.ts
/api/weather
Basic route
src/server/index.ts
/api
Root endpoint
src/server/users/index.ts
/api/users
index.ts = folder route
src/server/users/[id].ts
/api/users/:id
Dynamic parameter
src/server/webhooks/stripe.ts
/api/webhooks/stripe
Nested paths
server/weather.ts
/api/weather
Legacy path (also supported)
Supported extensions: .ts, .js, .tsx, .jsx. Other files (like .json or .md) in src/server/ (or server/) are ignored. PHP and WordPress are not supported inside vibes or Pulses; .php files, WordPress themes/plugins, and WordPress admin routes are treated as unsupported source or scanner traffic.
Dynamic Route Parameters
Use square brackets [param] in filenames to create dynamic route segments. These become :param in the URL and are accessible in your handler.
src/server/users/[id].ts -> /api/users/:id
// File: src/server/users/[id].ts
// Route: /api/users/:id
import { definePulse } from "@vibecodr/pulse";
export default definePulse(async (input, env) => {
// Access the dynamic parameter from the request URL
const url = new URL(env.request.url);
const id = url.pathname.split("/").pop(); // "123" from /api/users/123
return { userId: id, message: "Found user" };
});
[id].ts matches /api/users/123, /api/users/abc, etc.
[...slug].ts catch-all routes are not currently supported
Project Types
Vibecodr automatically detects your project type based on file structure:
V
Vibe
Browser-only. No src/server/ (or server/) files.
Slot cost: 0 (unlimited)
P
Pulse
Server-only. Has src/server/ (or server/) files, no frontend entry.
Slot cost: 1 deployment slot
C
Combo
Full-stack. Frontend entry + src/server/ (or server/) files.
Slot cost: 1 deployment slot
Deployment slots limit how many pulse/combo projects you can have deployed at once. Free: 3 slots, Creator: 15 slots, Pro: 50 slots.
Creating Pulse Files
In Studio, create endpoints by adding a file under src/server/ (or server/). Use Configure → API → New endpoint, or right-click the folder in the file tree.
New API endpoint
This creates a new endpoint file with boilerplate code and shows the derived /api/* route.
Default pulse template
// src/server/my-endpoint.ts
// Route: /api/my-endpoint
import { definePulse } from "@vibecodr/pulse";
export default definePulse(async (input, env) => {
// Your logic here
return { message: "Hello from my-endpoint!" };
});
Advanced SQL compatibility is exposed as env.db on eligible plans. Use that surface only when you truly need SQL, treat it as advanced compatibility rather than the default Pulse backend model, and do not assume automatic Pulse State migration.
Handler Styles (Recommended)
We recommend using the definePulse helper to explicitly set your handler style. This ensures your code runs exactly as expected, even if you use default parameters or specialized bundlers.
Enhanced Style
Receives parsed input and Pulse backend capabilities. Best for business logic, policy fetch, connected accounts, and structured logs.
Enhanced handler
import { definePulse } from "@vibecodr/pulse";
export default definePulse(async (input, env) => {
env.log.info("pulse.received", {
method: env.request.method,
hasName: typeof input?.name === "string",
});
return {
greeting: `Hello ${typeof input?.name === "string" ? input.name : "there"}`,
region: env.pulse.DEFAULT_REGION ?? "global",
};
});
Web-Standard Style
Receives a standard Request and returns a Response. Best for proxying, streaming, or full control over HTTP headers.
Web-standard handler
import { defineWebPulse } from "@vibecodr/pulse";
export default defineWebPulse(async (req) => {
const body = await req.json();
return Response.json({ echo: body });
});
Legacy: Auto-detection
If you don't use the definePulse helper, the runtime guesses the style based on your function's argument count. This works for basic cases but can be brittle.
// Enhanced style: 2 arguments (input, env)
export default async function(input, env) { ... }
// Web-standard style: 1 argument (request)
export default async function(request) { ... }
Warning: Footguns
- Default parameters (e.g.,
(input, env =)) change the argument count and may cause your handler to run in the wrong mode. - Rest parameters (e.g.,
(...args)) report 0 arguments and will default to "web" style. - Wrappers (e.g.,
withAuth(handler)) can hide the true argument count.
Fix: Always use definePulse() or defineWebPulse() to avoid these issues.
Deployment Flow
When you publish a project with pulse files, here's what happens:
1
Project type detection
Vibecodr scans for src/server/ (or server/) files and classifies as Vibe, Pulse, or Combo.
2
Slot check
If pulse/combo, checks if you have available deployment slots.
3
Bundle & deploy
Your code is bundled with the Vibecodr runtime and deployed automatically by Vibecodr (no manual deploy wiring).
4
Verification
Vibecodr verifies the deployed endpoint responds before marking the Pulse active.
5
Status update
Pulse status set to "active" (success) or "failed" (error).
Troubleshooting
Pulse not detected
- Make sure your file is inside
src/server/(orserver/) - Check file extension is
.ts,.js,.tsx, or.jsx - Verify you have a default export function
Deployment failed
- Check Studio console for error messages
- Verify no syntax errors in your pulse code
- Ensure you haven't exceeded your deployment slot limit
Route not working
- Check the pulse status is "active" in Studio
- Verify the route matches your file path (see mapping table above)
- Try re-publishing the project
Best Practices
Routing Guidelines
- Use
index.tsfor collection endpoints (/api/users) - Use
[id].tsfor item endpoints (/api/users/:id) - Group related endpoints in folders (
src/server/webhooks/) - Keep file names lowercase with hyphens (
process-order.ts) - Avoid deeply nested routes - 2-3 levels is usually enough
- Use the Enhanced handler style for access to
env.pulse,env.secrets,env.connections,env.fetch,env.log, andenv.request.
File-to-route mapping
Pulse routing maps server-side source files to same-origin /api endpoints. The route shape should be predictable enough that vibe code, embeds, docs, and automation can call it without guessing where behavior lives.
Route collisions and unclear ownership become production bugs quickly. Name endpoints around behavior and keep handler files close to the capability they own.
- Keep Pulse routes stable once public callers depend on them.
- Avoid overlapping route names with different auth expectations.
- Use `.ts`, `.js`, `.tsx`, or `.jsx` for Pulse route files; PHP and WordPress are not supported inside vibes or Pulses.
- Document payload shape and error behavior for each public endpoint.
Exposure model
A deployed Pulse endpoint can be public HTTP while the source remains private. Those are different visibility planes. Do not rely on source privacy as endpoint access control.
If a route should be owner-only, signed, or session-gated, enforce that in the handler.
- Public callable does not mean public source.
- Public source does not mean safe to expose secrets.
- Runtime routing should not leak platform capabilities, deployment details, or logs.
Example and read next
Example: server/contact.ts should become a stable same-origin route such as /api/contact. Keep route names intentional, avoid collisions, and update callers when the route contract changes.
Use these related pages when you need the next layer of guidance. They point to the most likely follow-up tasks, not every page that happens to touch the same system.
- Read next: Pulse SDK & Handlers
- Read next: Calling Pulses
- Read next: Vibes & Pulses
- Read next: How-To Guides