Sign up for Gaplessly product updates (public)
/api/newsletterThe marketing footer's newsletter sign-up, double opt-in with all state in Resend (lib/marketing/newsletter.ts): a new address becomes a Resend contact with unsubscribed: true and is mailed a confirmation link carrying the contact id; nothing is subscribed until POST /api/newsletter/confirm. A still-pending address gets the link again (Resend's own idempotency key limits that to once per 24h); a confirmed subscriber is sent nothing. Rate-limited (newsletter: bucket, 5/min-window/IP) and bot-checked (guestBotCheck(), registered in bot-paths.ts), since it mails whatever address it is given. Answers {ok:true} for new, pending and confirmed addresses alike, so it cannot be used to learn who is on the list. A form-encoded body (the footer form before hydration) gets a 303 to /newsletter/confirm?status=sent instead of JSON.
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/newsletter" \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com" }'{ "ok": true}Request beta access (public) POST
The public entry point for the beta-access gate (book_beta_access_requests/book_beta_codes, migration 0188): `POST /api/onboarding/complete` refuses to create a brand new tenant without a valid, unredeemed code, and this is how a prospect asks for one. Rate-limited (`beta-request:` bucket, 5/min-window/IP via the same `consumeBucket()` the guest booking surface uses) and bot-checked (`guestBotCheck()`, registered in `bot-paths.ts`). Always answers `{ok:true}` regardless of outcome, whether fresh, a resubmission of an already-pending request (23505 on the partial-unique index, swallowed), or auto-approved, so the response can never be used to enumerate which emails have already asked or which auto-approve rules exist.
Confirm a newsletter sign-up (public) POST
The confirmation page's button: flips the Resend contact named by `id` (from the emailed link) to subscribed. Form-encoded, answered with a 303 back to `/newsletter/confirm` (`?status=done`, or `?id=...&status=failed`), never JSON. POST only; the page GET renders and writes nothing, because mail scanners fetch every link in an email unprompted. The contact id is a random uuid only Resend and the address owner see, so it is the whole credential; anything that is not a uuid is refused without calling Resend. Rate-limited (`newsletter-confirm:` bucket, 10/min-window/IP).