getEmailPreferences
Read a guest's email-preference flags by HMAC token (unauthenticated, CAN-SPAM compliant).
POST /getEmailPreferences Anonymous endpoint backing the unsubscribe link in every lifecycle email. Gated on a short-lived HMAC-SHA256 token bound to a userId + 30-day expiry + scope="email-prefs", signed with EMAIL_PREFS_SECRET. Rate-limited to 20 calls per IP per hour, fail-open to never block a legitimate opt-out.
AUTH NOTE
No Firebase Auth required. Gated on a short-lived HMAC-signed token that the platform embeds in the relevant link (unsubscribe email, etc.).
Request
| Field | Type | Required | Description |
|---|---|---|---|
token | string | yes | HMAC-SHA256 signed token in `payload.sig` format. Max 4096 chars. |
EXAMPLE BODY
{
"token": "eyJ1c2VySWQiOiJ1XzAxSFY5WFQiLCJleHAiOjE3MTk1MDA4NjAwMDAsInNjb3BlIjoiZW1haWwtcHJlZnMifQ.x7Hk9aBcDeFgHiJkLmNoPqRsTu0"
} Response
| Field | Type | Always present | Description |
|---|---|---|---|
email | string | yes | The user's email address. Returns empty string if user doc not found. |
preferences.lifecycle | boolean | yes | Lifecycle drips (welcome, first event, pre-event nudges, dormant tenant). |
preferences.transactional | boolean | yes | Always true — receipts, password resets, security alerts are legally required. |
preferences.recap | boolean | yes | Post-event recap emails sent by event organizers. |
preferences.marketing | boolean | yes | Product news, releases, and announcements. |
EXAMPLE BODY
{
"email": "[email protected]",
"preferences": {
"lifecycle": true,
"transactional": true,
"recap": true,
"marketing": false
}
} curl
curl -X POST https://us-central1-freedomgrc-photowall.cloudfunctions.net/getEmailPreferences \
-H "Content-Type: application/json" \
-d '{"data":{"token":"<your-prefs-token>"}}' JavaScript
We don't ship a first-party JS SDK yet (it's on the roadmap).
For callable endpoints, the Firebase Functions SDK is the recommended
path — it handles ID-token attachment and payload framing.
Plain fetch works too.
const response = await fetch(
'https://us-central1-freedomgrc-photowall.cloudfunctions.net/getEmailPreferences',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: { token: prefsToken } }),
},
);
const { result } = await response.json();
// result === { email: '...', preferences: { ... } } Error cases
| Code | When |
|---|---|
invalid-argument | Token missing or longer than 4096 chars. |
permission-denied | Token signature invalid, expired, or wrong scope. Single message — does not leak which check failed. |
internal | Firestore user lookup failed. Sentry-reported. |
Need a different shape?
The API surface is small. Tell us what you need and we'll work backward from your integration.