For developers

One POST. We keep the count.

Unwaited is a waitlist backend with an optional widget. Render your own form, send JSON to one endpoint, and let us handle order, capacity, dedupe, bots, and notifications.

unwaited.com/w/api-preview

40 already joined

The problem

Every waitlist you build is the same 400 lines nobody wants to own

A table, a unique index on email, and a counter that races under load. A captcha you bolt on after the first bot run. A CSV export marketing asks for on Friday. Unwaited is that code, done once, behind a JSON endpoint.

The recipe

Exactly what the button sets up

Capacity, reset time, opening hours, and the form fields. It is a starting point, not a cage. Every value is editable in Settings and the builder.

Recipe

API preview

  • No cap. The list stays open until you pause it.
  • No opening hours.
  • Asks for stack and GitHub handle, both optional.
  • The position is returned in the API response and shown on the success screen.
  • The running count is shown on the form and returned by the API.
Capacity
Unlimited
Signups open
Any time
Form asks for
Email, Stack, GitHub handle
Counter on the form
Shown
Create this waitlistSign in, one click, and it's live with these settings. Change anything after.

How it works here

How the list works

POST JSON

Field keys are yours. Numbers can arrive as strings, checkboxes as "on". We coerce like a browser would.

Get a position back

201 with position, or 200 already_joined with the existing one. Full, paused, and closed are explicit codes.

API keys skip the captcha

Server-to-server calls use a Bearer key. Browser calls send a captcha token.

Signed webhooks

On Pro, HMAC-SHA256 over a timestamp and the raw body. Retries with backoff, redeliver from the dashboard.

Fetch the form definition

GET the schema and theme and render it yourself, or hydrate a native form.

Plain HTML fallback

A form with action set to the endpoint works with no JavaScript. It redirects back with the result.

Why it holds up

What matters most

Correct under concurrency

Positions and capacity are decided under a database row lock. Fifty concurrent joins at capacity 10 get exactly 10.

Predictable errors

validation_failed lists the fields. waitlist_full and waitlist_closed carry reopensAt. Nothing is a 500 by design.

Recurring capacity is built in

Per day, week, or month with a time zone and reset time. You get windowLabel and reopensAt in every response.

The docs are the product

Every endpoint, header, and code on one page, with curl and fetch examples.

FAQ

Questions people here ask

Is there a client library?

Not yet. The endpoint is a single JSON POST. A fetch call is shorter than a library import.

What are the rate limits?

10 submits per minute per IP per waitlist and 120 per minute per waitlist. 429 comes with Retry-After.

Can I self-host?

No. The value is the hosted endpoint, the notifications, and the dashboard.

Does it email the people who join?

Yes: a confirmation with their number and a status link, which you can turn off per waitlist. For anything else, use the webhook to trigger your own email from Resend, Postmark, or whatever you already run.