Quickstart
Waitlist infrastructure for speed. You own the form. We own email, delivery tracking, and analytics.
1. Get an API key
Create an account, then create your first key under API keys. Keys look like
en_live_… and are server-side secrets.
The plaintext is shown once, at creation, and never again — only a hash is stored. Copy it straight into your secret manager; if you lose it, revoke the key and create another.
2. Create a waitlist
Once, in the dashboard or over the API. Reuse its id for every signup — you do not create a waitlist per person.
curl -X POST https://api.enlist.dev/v1/waitlists \
-H "Authorization: Bearer $ENLIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"my-launch"}'3. First signup
The API is plain REST, so this is the whole integration. No dependency required.
const response = await fetch('https://api.enlist.dev/v1/waitlists/WAITLIST_ID/signups', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ENLIST_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email: 'user@example.com', utm_source: 'producthunt' }),
});
const { id, position, total } = await response.json();
// Response is immediate. Email goes out with position in it. Dashboard tracks delivery.
// Re-submitting the same email returns the same position, no duplicate email.Wiring it into a form
A Next.js route handler on your backend. Your API key stays server-side. The browser gets the response — you render what you want, we track what lands.
export async function POST(request: Request) {
const { email } = await request.json();
const utmSource = new URL(request.url).searchParams.get('utm_source') ?? undefined;
const response = await fetch(
`https://api.enlist.dev/v1/waitlists/${process.env.WAITLIST_ID}/signups`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ENLIST_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, utm_source: utmSource }),
},
);
const { position, total } = await response.json();
return Response.json({ position, total });
}Customize signup emails
Open settings to edit the signup email subject and body. Use variables: {{waitlist_name}}, {{position}}, {{total}}, {{email}}. Plain text with auto-wrapped HTML.
Prefer a typed client?
TypeScript SDK
npm install @enlistdev/sdk — see the docs. Drop-in replacement for REST, so the
integration you build now stays the same.
Keep the key server-side
Call this from your server, not from browser JavaScript — a key shipped to the browser can be read by anyone. If you must call it from the client, proxy through a route on your own backend, as in the example above.
What happens on signup
- The signup gets the next position on that waitlist. Positions never shift.
- A signup email goes out — "You're on the list — you're #47 of 1203." Delivery and open state show up in the dashboard.
- Re-submitting the same email is a no-op: the original position comes back and no second email is sent.
utm_sourceis captured and rolled up in the stats endpoint.- A
referral_codecomes back in the response. Put it behind?ref=for a share link, and pass whatever arrives in?refback asreferral_codeon the next signup — see Referrals.
Using an AI coding agent?
Skip all of this. Add the MCP server and prompt your agent: "Add a waitlist to this project." Your agent wires everything in one message.