Misar IO Docs
MisarMailApi Reference

Email Preferences

Token-based email preference center — allow subscribers to manage their email preferences without login

The preferences API lets your subscribers update their own email preferences without logging in. Access is controlled by a signed token embedded in every unsubscribe and preference link MisarMail generates.

This is a token-based API — no API key or session cookie is required. The subscriber authenticates via a short-lived signed JWT included in outbound email links.

How the token works

Every email sent through MisarMail includes a unique, subscriber-specific signed JWT in the unsubscribe link:

https://mail.misar.io/preferences?token=eyJhbGciOiJIUzI1NiJ9...

The token encodes the subscriber's contact ID and expires after 7 days. An expired or tampered token returns 401.


Get preferences

GET /api/preferences?token=:token

Returns the subscriber's current category preferences and email frequency.

Response

{
  "success": true,
  "email": "u***@example.com",
  "preferences": {
    "marketing": true,
    "productUpdates": true,
    "newsletters": false,
    "transactional": true,
    "frequency": "weekly"
  }
}

The email field is masked for privacy — subscribers see enough to confirm it is their address. If the subscriber has never visited the preference center before, all categories default to true and frequency defaults to "immediate".


Update preferences

PUT /api/preferences
Content-Type: application/json

Request body

FieldTypeRequiredDescription
tokenstringYesThe signed JWT from the preference link
preferences.marketingbooleanNoMarketing and promotional emails
preferences.productUpdatesbooleanNoProduct news and feature announcements
preferences.newslettersbooleanNoNewsletter subscriptions
preferences.frequencystringNoimmediate | daily | weekly | monthly | never

transactional emails (password reset, receipts, security alerts) cannot be disabled. The field is read-only and always returned as true.

Request example

{
  "token": "eyJhbGciOiJIUzI1NiJ9...",
  "preferences": {
    "marketing": false,
    "newsletters": false,
    "frequency": "weekly"
  }
}

Response

{
  "success": true,
  "message": "Preferences updated",
  "preferences": {
    "marketing": false,
    "productUpdates": true,
    "newsletters": false,
    "transactional": true,
    "frequency": "weekly"
  }
}

Embedding a preferences link

MisarMail automatically adds unsubscribe and preference links when you send campaigns. For custom HTML emails, inject the link using the {{preferences_url}} merge tag:

<a href="{{preferences_url}}">Manage email preferences</a>

Generating tokens server-side

If you are building a custom preference center, you can generate a token via the contacts API and redirect the user to your own page:

curl -X POST https://api.misar.io/mail/v1/contacts/em_abc123/preference-token \
  -H "Authorization: Bearer msk_..."
{ "token": "eyJhbGciOiJIUzI1NiJ9...", "expires_at": "2025-06-21T10:00:00Z" }

Pass the token to your preference center page, then call PUT /api/preferences with it directly.


Security

  • Email addresses are masked in GET responses (u***@example.com) to prevent email harvesting via leaked tokens
  • Tokens are signed with HMAC-SHA256 and include an expiry — they cannot be forged or extended
  • The endpoint is rate limited by IP to prevent token enumeration attacks
  • Invalid or expired tokens return 401 Unauthorized with no further detail

Example

# Get preferences
curl "https://api.misar.io/mail/api/preferences?token=eyJhbGciOiJIUzI1NiJ9..."

# Update preferences
curl -X PUT https://api.misar.io/mail/api/preferences \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJhbGciOiJIUzI1NiJ9...",
    "preferences": { "marketing": false, "frequency": "weekly" }
  }'
// Typically called from your preference center page
const token = new URLSearchParams(window.location.search).get('token');

// Fetch current preferences
const res = await fetch(`/api/preferences?token=${token}`);
const { preferences } = await res.json();

// Save changes
await fetch('/api/preferences', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ token, preferences: { marketing: false } }),
});