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
| Field | Type | Required | Constraints |
|---|---|---|---|
email | string | yes | Valid email, ≤ 200 chars |
name | string | no | ≤ 100 chars |
source | string | no | Attribution 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_KEYis 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
| Name | Type | Description |
|---|---|---|
email | string | Subscriber email (URL-encoded). |
token | string | HMAC-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)
| Status | Cause |
|---|---|
400 | Invalid JSON, missing/ invalid email. |
429 | Rate limit exceeded. |
500 | Database failure. Retry the request. |
Managing subscribers (manager only)
The Manager dashboard provides a UI for listing, reactivating, and deleting subscribers at /dashboard/newsletter.