Skip to content

Integration  ·  Legal and compliance

How to build a consent and preference sync

Somebody unsubscribes and gets another email nine days later because a second system never heard about it. The thinking behind consent that propagates, the prompts that build it, and what it takes to keep it running.

Built with Tray Headless

  1. System Preference centre
  2. Step Consent store
  3. Step Propagate now
  4. System Marketo
  5. System Salesforce
Also Evidence log

One system owns consent and every other one reads it, with withdrawal propagating in seconds instead of on the next nightly run.

The short answer

What is a consent and preference sync?

Four things make up a consent and preference sync: one authoritative store instead of consent living in several systems, withdrawal propagating in seconds instead of on a nightly schedule, evidence recorded for every change including how it was captured, and a suppression check at send time rather than at list build. Most of these come apart on bidirectional sync. Letting two systems both write consent means one of them will eventually re-subscribe somebody who opted out, and that is a regulatory problem rather than a bug.

What matters here

  • Give consent exactly one authoritative store. Two systems that both write it will eventually re-subscribe somebody.
  • Propagate withdrawal in seconds. A nightly sync means somebody who unsubscribed on Monday is emailed on Tuesday.
  • Record how consent was captured, not just that it exists. The evidence is what makes it defensible.
  • Check suppression at send time, not at list build. A list built yesterday does not know about today withdrawal.
  • Granular preferences beat a single flag. Somebody who wants product updates and not events should get exactly that.

Who this is for

You run marketing operations, privacy or revenue operations. Consent lives in three systems, they disagree, and nobody is certain which one an auditor would accept.

How it works in practice

What happens between somebody changing their mind and every system honouring it.

  1. 1

    One store is authoritative for consent

    Every other system reads from it and none of them write to it.

  2. 2

    A change is captured with its evidence

    Timestamp, source, IP or channel, the exact wording shown, and the version of it.

  3. 3

    Withdrawal propagates within seconds

    Push, not a nightly pull, because the gap between them is where the violation happens.

  4. 4

    Preferences are granular, not one flag

    Product updates, events, research and transactional, each held separately.

  5. 5

    Suppression is checked at send time

    A list built yesterday cannot know about a withdrawal this morning.

  6. 6

    Every change is retained as evidence

    Longer than the consent itself, because the question comes after the relationship ends.

What consent sync is made of

Four parts, and the first one prevents the regulatory failure.

One authoritative store

Consent has a single writer. Every other system reads. Bidirectional consent sync eventually re-subscribes somebody who opted out.

Immediate withdrawal

Pushed within seconds. A nightly reconciliation guarantees a window where a withdrawal is not yet honoured.

Recorded evidence

When, how, through which channel, and the exact wording shown. That the box was ticked is not evidence; what it said is.

Send-time suppression

Checked against the store at send, not at list build, because the list was correct yesterday and is not now.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Start here: choose one owner

    This decision prevents the regulatory failure. Nothing else does.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Marketo, Salesforce and
    our preference centre, or whatever we run in those seats.
    
    Show me every field in every system that currently expresses consent or
    subscription state. There will be more than expected and they will
    disagree.
    
    Then help me pick exactly one authoritative store. Everything else reads
    from it and nothing else writes to it.
    
    This is the whole design. Two systems that both write consent will
    eventually disagree, and the direction that hurts is the one that
    re-subscribes somebody who opted out.

    Whichever store you choose, the preference centre should write to it directly rather than to a system that syncs to it. Every hop is a window where a withdrawal is not yet honoured.

  2. 2

    Capture evidence, not only state

    That the box was ticked is not evidence. What it said is.

    Headless skills build-workflow

    Use build-workflow. On every consent change record:
    
      Who, timestamp, and which preference changed
      Whether it was given or withdrawn
      The channel: preference centre, form, unsubscribe link, support agent,
      import
      The exact wording shown at the time, and its version
      IP address and user agent for a web capture, where lawful to keep
    
    Store the wording version, not a link to current wording. Consent
    text changes, and evidence that points at today's wording proves nothing
    about what somebody agreed to two years ago.
    
    Never overwrite a consent record. Append. The history is the evidence and
    the current state is a view over it.
  3. 3

    Propagate withdrawal in seconds

    The gap between systems is where the violation happens.

    Headless skills tray-patterns

    Push a withdrawal to every downstream system immediately, not on a
    schedule.
    
    Suppress in the marketing platform, the CRM, the sales engagement tool,
    any ad audience, and the support tool if it sends proactive email.
    
    Confirm each propagation and alert on any that fails instead of letting
    it retry quietly. A withdrawal that failed to reach one system is the one
    that sends the email.
    
    Grants can propagate on a normal schedule. Withdrawals cannot. That
    asymmetry is deliberate: the cost of a slow grant is a delayed newsletter
    and the cost of a slow withdrawal is a regulatory complaint.
  4. 4

    Keep preferences granular and check at send

    A list built yesterday does not know about this morning.

    Headless skills tray-gotchas

    Use tray-gotchas, then hold preferences granularly rather than as one
    flag: product updates, events, research, partner communications, and
    transactional separately.
    
    Somebody who wants release notes but not event invitations should get
    exactly that. A single subscribe flag forces people to choose all or
    nothing, and most choose nothing.
    
    Then check suppression at send time against the authoritative store, not
    at list build. A campaign list assembled yesterday does not know about a
    withdrawal this morning.
    
    Handle: transactional messages, which are not marketing and follow
    different rules, so classify them explicitly; a double opt-in that was
    never confirmed, which is not consent; and consent that has expired under
    a regime that time-limits it.
  5. 5

    Reconcile, and keep the evidence longer than the consent

    Because the question arrives after the relationship ends.

    Reconcile daily between the authoritative store and every downstream
    system. Report anybody suppressed in one and not another, in both
    directions.
    
    The dangerous direction is somebody withdrawn centrally and still
    subscribed downstream. Alert on that immediately instead of reporting
    it.
    
    Retain the evidence longer than the consent itself. A complaint about an
    email arrives after somebody has left the database, and the record has to
    outlive the relationship to answer it.
    
    Report: consent by channel and preference, withdrawal rate, propagation
    failures, reconciliation differences, and how long a withdrawal takes to
    reach every system.
  6. 6

    Prove it works, then hand it to privacy and marketing together

    Because it is a compliance rule with a marketing consequence.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production. Test the withdrawal path end to end and measure how
    long it takes to reach the last system.
    
    Then open the same workflow in Tray Build so privacy and marketing
    operations can adjust preference categories and consent wording versions
    together in the visual canvas. Neither team should be able to change it
    alone.

What it connects to

One store writes, everything else reads, and withdrawal reaches all of them at once.

Marketo

Read consent from the authoritative store and suppress on it. Never the source of truth for consent itself.

Reads and writes

Salesforce

Display consent state read-only on the contact, so a rep can see it and cannot change it.

Writes

Outreach

Suppress immediately on withdrawal, because sales engagement tools are the most common source of a post-unsubscribe email.

Writes

Snowflake

Hold the append-only evidence log, retained longer than the consent itself.

Reads and writes

Zendesk

Read consent before any proactive outbound, and never let a support action change it.

Reads

Slack

Alert on a propagation failure, because a withdrawal that did not land is the one that sends the email.

Writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, Jira, HubSpot or Databricks.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This is a regulatory control. The failure mode is a complaint you cannot answer.

It runs where production runs, not on a laptop

Withdrawal propagation fires within seconds of a change, at any hour, with retries and confirmation per destination.

The evidence outlives the relationship

Append-only, with the wording version shown at capture. Evidence pointing at today wording proves nothing about a consent given two years ago.

No credential ever lands in the workflow itself

Consent write access is the most sensitive permission in the marketing stack. Held in your workspace, scoped, and never shared with a campaign tool.

Privacy and marketing own it together

Preference categories and wording versions open in Tray Build, and neither team should be able to change them alone.

Withdrawals never wait for a schedule

Grants can propagate on a nightly run. Withdrawals cannot, and that asymmetry is the entire point.

Questions people ask

Why can only one system own consent?

Because two systems that both write it will eventually disagree, and the direction that hurts is the one that re-subscribes somebody who opted out. That is a regulatory problem, not a data quality one.

Why must withdrawal propagate immediately?

Because a nightly sync guarantees a window in which somebody who unsubscribed has not yet been suppressed. Grants can wait; withdrawals cannot, and the asymmetry is deliberate.

What evidence should be recorded?

When, through which channel, and the exact wording shown at the time with its version. That a box was ticked is not evidence; what the box said is, and consent wording changes.

Why check suppression at send time?

Because a campaign list built yesterday does not know about a withdrawal this morning. Checking at list build is how a compliant process still sends the email.

Why granular preferences?

Because a single subscribe flag forces people to choose all or nothing, and most choose nothing. Somebody who wants release notes but not event invitations should be able to have exactly that.

Last reviewed September 2026.