Unsubscribe link
- Token = HMAC-SHA256(
${subscriberId}.${expiresAt}, secret = MAILGUN_WEBHOOK_SIGNING_KEY).
- URL:
https://fogserv.cloud/api/email/unsubscribe?sub=<id>&exp=<ms>&token=<hex>.
- Endpoint validates:
sub exists.
exp > Date.now() (default 90 days).
crypto.timingSafeEqual of recomputed token.
- On success:
prisma.subscriber.update status='UNSUBSCRIBED', unsubscribedAt=now().
- One-click per RFC 8058 —
List-Unsubscribe-Post: List-Unsubscribe=One-Click header is also set by mailgun template; the GET endpoint above is the human fallback.
// /api/email/unsubscribe — sketch
const sub = req.query.sub as string
const exp = Number(req.query.exp)
const token = req.query.token as string
const expected = hmac(sub + '.' + exp, process.env.MAILGUN_WEBHOOK_SIGNING_KEY!)
if (!safeEqual(token, expected) || Date.now() > exp) return res.status(400).end()
await prisma.subscriber.update({ where: { id: sub }, data: { status: 'UNSUBSCRIBED', unsubscribedAt: new Date() } })
return res.status(200).send('Unsubscribed.')