The promotions module covers customer-side subscriptions to marketing programmes — newsletters, drip campaigns, loyalty tiers, opt-in lists. It is distinct from commerce subscriptions (recurring product billing) and from subscription plans on the org-management side. Use this for "subscribe to our weekly digest" and "join our VIP rewards programme".
Subscribe and confirm
/crm/promotions/:name/subscribeNo auth/crm/promotions/confirm/:tokenNo auth/crm/promotions/:name/unsubscribeNo authPublic so a marketing site or storefront footer can call them without auth. subscribe accepts an email and optional metadata; the platform sends a confirmation email with a tokenised link, and confirm/:token flips the subscription to confirmed. This is double-opt-in by default — required by GDPR and most major email vendors.
await fetch(`/api/crm/promotions/weekly-digest/subscribe`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', orgid: ORG_ID },
body: JSON.stringify({
email: '[email protected]',
name: 'Alice',
metadata: { source: 'footer-form' },
}),
});
unsubscribe is by email — the unsubscribe link in every marketing email points at this endpoint with the email hashed into the URL.
Promotion CRUD
/crm/promotionsJWT/crm/promotionsJWT/crm/promotions/:nameJWT/crm/promotions/:nameJWT/crm/promotions/:nameJWTA promotion body:
{
"name": "weekly-digest",
"title": "Weekly Digest",
"description": "Hand-picked stories every Monday.",
"doubleOptIn": true,
"incentive": {
"type": "discount-code",
"value": "WELCOME10",
"amount": 10,
"currency": "USD"
},
"tags": ["newsletter", "weekly"]
}
Setting an incentive means new subscribers get a reward on confirmation — a discount code, a downloadable asset, or credit to their wallet. The incentive-claimed endpoint records that the reward was issued so you don't double-grant.
Subscriber management
/crm/promotions/:name/subscribersJWT/crm/promotions/:name/incentive-claimedJWTSubscribers list with pagination, filtering by status (pending, confirmed, unsubscribed, bounced). Use this list as the audience for Marketing campaigns — the campaign builder accepts a promotion name as a shortcut for "all confirmed subscribers".
Customer preferences
/crm/promotions/preferencesJWTReturns the current customer's full subscription state across every promotion in the org — which they're on, which they've left, which they're pending. A "manage preferences" page in your customer portal calls this.
Promotion as audience
A promotion is implicitly an audience: confirmed subscribers form a dynamic list. The Marketing module's audience picker shows promotions alongside saved segments. Cross-link them by passing audienceType: "promotion" and audienceId: <promotion-name> when creating a campaign.
Compliance
Every subscription stores consentedAt, consentSource, consentIp, and the unsubscribe history. When a customer requests a data export under GDPR, the platform pulls these fields automatically. Bounced and unsubscribed addresses are excluded from sends — the sync queue blocks them at dispatch time, not at audience-evaluation time, so you can safely target a stale list.
Disabling doubleOptIn is supported but not recommended. Major mailbox providers (Gmail, Outlook, Yahoo) will throttle or block senders whose lists show high single-opt-in volume.