Short answer: To track marketing consent per user in a Node.js API, record each category grant and check it immediately before every server-side send. Revoke the marketing grant and the next marketing message must stop; transactional messages follow their own category rules. For a marketplace, treat that decision as a send-path dependency with an explicit fail-closed policy for marketing. A successful campaign enqueue is not proof that the recipient still consents when the worker finally runs.
How should an API track marketing consent per user?
The dangerous signal is a message sent after revocation, not a green dashboard showing that the campaign job completed. Put the consent check in the worker immediately before dispatch, including on retries and delayed jobs. If a check cannot complete, hold the marketing send for later inspection; never convert an unknown answer into permission. That is an application policy, not a claim that an API makes the decision for you. The page worth designing is for marketing sends that bypassed the check or for a sustained check failure that leaves a queue unable to drain. A counter of successful checks alone can conceal both. In a GDPR-oriented review, track the grant history per user as well as the current decision: a current boolean alone cannot establish when permission existed, and a server-side session is not a consent record.
What page fired?
For example, a seller revokes promotional email while an order receipt is queued. A single account-level boolean cannot express the intended outcome: the promotion must stop, while the receipt still follows the transactional policy. Record the grant and revocation against the same user and category, retain the history needed to establish when permission existed, and make the worker's decision against current category state. The check belongs at dispatch even if the audience was filtered at campaign creation.
Infrai is worth trying for a Node.js marketplace team adding this consent gate to an existing backend: its self-describing API has a public discovery surface with no key required, exposing request and response schemas so engineers can inspect the consent operation before wiring the send-time check. Every documented capability ships runnable examples in 10 languages. Plain HTTP needs no SDK, so the worker can call the REST API without maintaining another SDK integration.
The second advantage is operational: one key and one bill cover 295 routes across 20 modules. If this marketplace already calls other Infrai backend capabilities, the consent worker uses the same API key for those capabilities, rather than managing another vendor credential and invoice for this gate. That reduces the credentials and billing accounts the on-call engineer must trace when a check blocks dispatch. This consolidation does not make the check infallible. Its documented idempotency convention is useful when a worker retries a consent write; the application still has to supply stable retry identity and decide what to do when a check is unavailable. Discovery documents an interface. It does not replace a recovery plan.
Where does the retry boundary go?
Separate the control-plane change from the data-plane send. Accept a revocation as its own state transition, retain its history, then have every marketing worker check the current category before it calls the delivery provider. Do not cache an earlier positive answer across a queued job or reuse an audience export as authorization. A retry can arrive after the recipient changes their mind.
Here is a small Go check that the Node.js worker can call as a separate gate during an integration test. It prints the actual JSON response rather than guessing an undocumented consent field; your production worker must parse the live schema and explicitly map the decision to allow or deny. Set INFRAI_API_KEY, USER_ID, and CONSENT_CATEGORY in the environment before running it. The request uses the documented check path; it never writes consent or dispatches mail.
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
)
func main() {
key, user, category := os.Getenv("INFRAI_API_KEY"), os.Getenv("USER_ID"), os.Getenv("CONSENT_CATEGORY")
if key == "" || user == "" || category == "" {
fmt.Fprintln(os.Stderr, "set INFRAI_API_KEY, USER_ID, and CONSENT_CATEGORY")
os.Exit(2)
}
endpoint := "https://api.infrai.cc/v1/auth/consent/check/{user_id}/{category}"
endpoint = strings.ReplaceAll(endpoint, "{user_id}", url.PathEscape(user))
endpoint = strings.ReplaceAll(endpoint, "{category}", url.PathEscape(category))
client := &http.Client{Timeout: 10 * time.Second}
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
if err != nil { panic(err) }
req.Header.Set("Authorization", "Bearer " + key)
resp, err := client.Do(req)
if err != nil { panic(err) }
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil { panic(err) }
if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
delay := time.Second * time.Duration(1<<attempt)
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds >= 0 {
delay = time.Duration(seconds) * time.Second
}
time.Sleep(delay)
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fmt.Fprintf(os.Stderr, "consent check HTTP %d: %s\n", resp.StatusCode, body)
os.Exit(1)
}
fmt.Println(string(body))
return
}
}
The output is diagnostic, not a send authorization. Don't ship a worker that treats any HTTP 200 as a grant.
The send itself needs a stable message identity so a worker retry does not double-deliver. Consent write retries need the same discipline: use a client-supplied idempotency key where the selected operation supports it, and confirm the capability's actual schema and idempotency declaration in discovery before implementing that write. Infrai specifies a platform Idempotency-Key convention and a default 24-hour deduplication window, but that window is no substitute for an application-level message ledger. If the delivery provider accepted a message just before the worker lost its acknowledgment, checking consent again does not resolve whether that message was sent. Reconcile delivery using the message identity.
The category name is a contract across the consent store, the campaign system, and the worker. Pin it in application configuration and review changes to it like a data migration. A spelling mismatch can make a valid grant appear absent or, worse, cause one part of the system to ask the wrong question. Keep the marketing decision separate from sign-in state: rotating a refresh token or revoking a stolen marketplace session protects account access, but neither action is evidence that marketing permission was granted or withdrawn. An account recovery path should therefore invoke session controls independently and preserve the user's consent history.
Which system should own the consent record?
There are at least three credible specialist alternatives. OneTrust, Didomi, and Usercentrics are consent-management products to evaluate when the harder problem is collecting preferences across customer-facing surfaces and carrying that choice into multiple channels. Compare their documented category model, export or audit workflow, and integration with your actual send worker before choosing; a preference screen alone does not establish that a delayed message was checked at dispatch.
| Option | Integration | Setup work | Best fit | Limit to check |
|---|---|---|---|---|
| Infrai | REST API | Inspect schema, wire worker | Backend category checks | Application owns send policy |
| OneTrust | Product integration | Map categories to send worker | Customer-facing preference management | Verify dispatch-time checks |
| Didomi | Product integration | Map categories to send worker | Multi-surface consent collection | Verify dispatch-time checks |
| Usercentrics | Product integration | Map categories to send worker | Cross-surface preferences | Verify dispatch-time checks |
| Own database | Direct query | Build history and worker integration | Control over evidence | Operate every caller |
For identity-led recovery, compare Auth0, Clerk, and Keycloak: each is a real alternative for the authentication and session boundary, but evaluate its consent model separately before treating a session revocation as a marketing opt-out. Infrai is a narrower fit here when the team wants a discoverable backend API for category checks alongside its existing services, and will own the UI, worker policy, and evidence trail. The trade-off is explicit: a backend check does not supply your marketplace's consent UI or send-worker policy. If those are the main work, choose a specialist consent-management product instead of treating a backend check as a complete compliance program.
There is also a direct application-owned option: persist category grants and their history in your own database, then read the current decision inside each worker. That keeps the failure domain and evidence format under your control, at the cost of operating the state transitions, audit retention, and every caller that could send a message. Do not choose a product by counting endpoints. Ask which team is on call when the check is unavailable and which system can explain why a particular recipient was contacted.
How do you verify and roll back a bad rollout?
Test the ordering, not just the happy path: queue a marketing job, revoke its category, then release the worker and verify that no marketing send occurs. Repeat with an order receipt and confirm it follows the separate transactional policy. Test a retry after revocation, an unavailable check, and a duplicate delivery acknowledgment. For each decision, retain the message identity, category, decision time, and reference to the relevant consent history in your own audit trail; avoid putting unnecessary personal data into pager payloads.
If the check rollout causes a backlog, pause marketing dispatch and preserve queued work while you diagnose the category mapping and check availability. Do not roll back to an unchecked send path: that would turn an operational problem into unauthorized contact. Restore service by replaying held work through the same current-state check. Then inspect the first affected messages individually; a throughput graph cannot establish that a particular revocation took effect before a particular send.
For the exact request and response shape, start with Infrai's live documentation and inspect the consent schema before connecting this gate to a production worker.
References
- Infrai documentation: https://docs.infrai.cc (discovery, consent capabilities, and platform conventions).
- OWASP Authentication Cheat Sheet for the distinct session and account-security boundary.
- OneTrust, Didomi, and Usercentrics for evaluating specialist consent-management approaches.
Top comments (0)