A server route in server/api runs on Nitro. Environment variables stay on the server — $fetch handles the rest.
import { Enlist } from '@enlistdev/sdk';const enlist = new Enlist({ apiKey: process.env.ENLIST_API_KEY! });export default defineEventHandler(async (event) => { const { email } = await readBody(event); const signup = await enlist.waitlists.addSignup( process.env.WAITLIST_ID!, { email }, ); return { position: signup.position, total: signup.total };});What you get
Inside a locked transaction. The signup response already contains the position and total — no polling, no second request needed to render "you're #47".
Sent via your email provider with the position in the body. Delivery, open, and click state is written back onto the signup row.
REST, TypeScript SDK, and an MCP server for coding agents. All the same API key, all the same response shape.
Add the MCP server and prompt your coding agent — it creates the waitlist and wires the handler in one shot.