Newsletter API

Public, unauthenticated endpoints for managing newsletter subscriptions. The blog and landing apps share one subscriber table.

Subscribe

POST
https://eggisatria.dev/api/newsletter/subscribe

Request body

FieldTypeRequiredConstraints
emailstringyesValid email, ≤ 200 chars
namestringno≤ 100 chars
sourcestringnoAttribution tag (e.g. "landing-footer").

Example request

Terminal
curl -X POST https://eggisatria.dev/api/newsletter/subscribe \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada@example.com",
    "name": "Ada",
    "source": "docs"
  }'

Example response

JSON · 201 Created
{
  "success": true,
  "data": {
    "alreadySubscribed": false,
    "message": "Subscribed! Check your inbox for a welcome email."
  },
  "error": null
}

Behavior

  • Idempotent: re-subscribing returns alreadySubscribed: true.
  • Re-subscribing an unsubscribed address re-activates it.
  • If RESEND_API_KEY is set, a welcome email is sent with a one-click unsubscribe link. Otherwise the send is simulated and logged on the server.
  • Rate-limited per IP: 5 requests per 10 minutes.

Unsubscribe

GET
https://eggisatria.dev/api/newsletter/unsubscribe?email=<email>&token=<token>

Query parameters

NameTypeDescription
emailstringSubscriber email (URL-encoded).
tokenstringHMAC-SHA256 token from the welcome email — never store this client-side.

Example link (from a welcome email)

https://eggisatria.dev/api/newsletter/unsubscribe?email=ada%40example.com&token=4f3b…

Response

Always returns an HTML confirmation page (status 200, 400, or 500) so the user sees a friendly message — never a raw error.

Error responses (subscribe)

StatusCause
400Invalid JSON, missing/ invalid email.
429Rate limit exceeded.
500Database failure. Retry the request.

Managing subscribers (manager only)

The Manager dashboard provides a UI for listing, reactivating, and deleting subscribers at /dashboard/newsletter.