Skip to content

Newsletter signup

Capture email subscribers from your storefront. Signup is double opt-in: your storefront submits the email, the platform emails a confirmation link, and the subscriber becomes confirmed only after they click it. Examples reuse the api() helper.

Subscribe (public)

POST /api/v1/public/newsletter/subscribe — tenant header, no auth (it's a public capture, rate-limited per tenant).

await api("/public/newsletter/subscribe", {
  method: "POST",
  body: JSON.stringify({
    email: "dana@example.com",   // required, valid email — normalized to lowercase
    source: "footer",            // optional free-form capture-origin tag
  }),
});
// → { ok: true }

The response is always { ok: true } — it deliberately doesn't reveal whether that email was new, already pending, or already confirmed (so the endpoint can't be used to probe who's subscribed). A new email creates a pending subscriber and triggers the confirmation email; submitting an already-known email is an idempotent no-op (no duplicate, no second email mid-flight).

The double opt-in flow

  1. POST …/subscribe → subscriber stored pending, confirmation email sent.
  2. The email contains a confirm linkGET …/public/newsletter/confirm?token=…. The subscriber clicks it and becomes confirmed.
  3. Every email also carries a one-click unsubscribe linkGET …/public/newsletter/unsubscribe?token=….

The confirm and unsubscribe links are tokenized targets the platform emails — they're not endpoints your storefront builds or calls. Your integration is just the subscribe POST; the platform owns the confirmation + unsubscribe lifecycle (which is why those two routes aren't in the API reference).

Only confirmed subscribers are mailable, so a captured-but-unconfirmed email won't receive campaigns until the link is clicked.