Launching a Journey in Braze vs Salesforce Marketing Cloud: A Sweepstakes Example

Home / MarTech / Braze vs SFMC
Daniel Robles Published SFMC Braze

Someone fills out a sweepstakes form. A confirmation email should arrive in seconds, and a short series should follow: a bonus-entry reminder, a winner announcement, maybe an offer for people who opted in. It is about the simplest journey there is, and it is a good way to see how differently Salesforce Marketing Cloud and Braze think. This article builds the same launch on both platforms, step by step, with no CDP in the middle: your form, your backend, and the marketing platform. The difference that matters is not the UI. In SFMC the entry becomes a row in a data extension. In Braze it becomes an event on a person. That difference is the thread I will pull on in a follow-up about events versus data extensions, and it connects to Object Oriented Marketing and Marketing Eventing.

1. The scenario

A holiday sweepstakes with a landing page form. Four fields, two checkboxes, and one rule that trips teams up: entering cannot depend on opting in to marketing. The confirmation is transactional (the person asked for it); everything after it that promotes something is marketing and needs consent.

FieldExampleNotes
first_nameAnaPersonalization only
emailana@example.comRequired to enter and to notify a winner
zip94110Eligibility (many sweepstakes are US-only or exclude some states)
marketing_opt_intrue / falseOptional, never pre-checked, stored with a timestamp
rules_acceptedtrueRequired; links to the Official Rules

The form posts to your backend, never straight to the marketing platform. The backend validates and rate-limits the entry (sweepstakes attract bots), dedupes it, writes it to your own database, generates a stable entrant ID if the person has no account, and then hands a copy to SFMC or Braze. The platform is a consumer of the entry, not its system of record.

ONE FORM, TWO PLATFORMS, NO CDPformsweepstakes entrybackendform handlerSALESFORCE MARKETING CLOUD1 OAuth tokeninstalled package2 API Event/interaction/v1/eventsEntries DEa row per entryJourneyentry: API Eventemail%%FirstName%%setup: data extension, installed package, event definition, journey, re-entry rulesBRAZE1 REST API keyusers.track scope2 /users/trackattributes + eventuser profileevent on thetimelineCanvasaction-based entryemail{{first_name}}setup: API key, Canvas with a custom-event entryHover or tap any box. Orange: the entry becomes a row in a table. Blue: the entry becomes a fact on a person.
The same entry, launched into a journey on each platform. Hover or tap any box for the request, the setting or the gotcha behind it.

2. Salesforce Marketing Cloud: a journey fed by a data extension

The modern SFMC pattern for “something happened, start a journey” is a Journey Builder API Event entry source. Your backend calls one endpoint and the contact enters the journey. Under the hood, that event is an insert: Journey Builder writes the payload into a data extension and the journey reads from it. So the table comes first.

Step 1. Create the entry data extension

Name: Sweepstakes_EntriesSendable: ContactKey → Subscriber KeyRetention: delete rows after 180 days
FieldTypeLengthKeyRequiredNotes
EntryIdText50primary keyrequiredOne row per entry, so people can enter more than once
ContactKeyText254requiredYour stable entrant ID, not the email
EmailAddressEmailAddressrequiredWhere the email goes
FirstNameText100optionalPersonalization
ZipText10optionalEligibility checks
SweepstakesIdText50requiredWhich sweepstakes, e.g. holiday_2026
OptInBooleanrequiredMarketing consent from the checkbox
EnteredAtDaterequiredDefault value: current date

Every field the form will ever send must exist, with a type and a length, before the first entry. The primary key is EntryId, not ContactKey, so a person can enter more than once. ContactKey should be your stable entrant ID, not the email address: contact keys are permanent, emails are not.

Step 2. Create an installed package and get a token

An admin creates a server-to-server API integration under Setup, Apps, Installed Packages, with Journeys (read, execute) and Data Extensions (read, write) scopes. Your backend trades the client ID and secret for a short-lived token and caches it:

POST https://{subdomain}.auth.marketingcloudapis.com/v2/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "<installed package client id>",
  "client_secret": "<secret from your vault>",
  "account_id": "<business unit MID>"
}

Step 3. Build the journey on an API Event entry source

In Journey Builder, add an API Event entry source, bind it to Sweepstakes_Entries, and copy the generated EventDefinitionKey. Build the flow: confirmation email, wait three days, a decision split on OptIn, then the bonus-entry email. Set re-entry (no re-entry for one journey per person, or re-entry after exit for daily entries) and activate it.

Step 4. Fire the event from your backend

POST https://{subdomain}.rest.marketingcloudapis.com/interaction/v1/events
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "ContactKey": "c_20931",
  "EventDefinitionKey": "APIEvent-7c1e2f",
  "Data": {
    "EntryId": "ent_55120",
    "ContactKey": "c_20931",
    "EmailAddress": "ana@example.com",
    "FirstName": "Ana",
    "Zip": "94110",
    "SweepstakesId": "holiday_2026",
    "OptIn": true
  }
}

-> 201 { "eventInstanceId": "8f6e..." }

Every key inside Data must match a field in the data extension. An unknown field, a value longer than its column or a missing required field fails the call. A valid call against a paused or unpublished journey version still writes the row, and nobody enters, which is the bug teams find the morning after launch.

Step 5. Personalize from the row

Hi {{Event.APIEvent-7c1e2f."FirstName"}},

%%[ SET @sweeps = AttributeValue("SweepstakesId") ]%%
You're entered in the %%=ProperCase(Replace(@sweeps, "_", " "))=%% sweepstakes.
%%[ IF AttributeValue("OptIn") == "True" THEN ]%%
  Come back tomorrow for a bonus entry.
%%[ ENDIF ]%%

Emails read the row through Journey Data ({{Event.APIEvent-...}}) or AMPscript. Give the confirmation a transactional send classification; the follow-ups need a commercial one and must respect the subscriber's status.

3. Braze: a Canvas triggered by an event

Braze has no table to create. Your backend tells Braze two things in one request: what is true about the person (attributes) and what just happened (an event). A Canvas listens for the event.

Step 1. Create a REST API key

Under Settings, APIs and Identifiers, create a key with the users.track permission and store it in your vault. There is no token exchange; the key goes in the Authorization header.

Step 2. Build the Canvas on an action-based entry

Set the entry schedule to action-based, with the trigger “performs custom event sweepstakes_entered”, optionally filtered on the property sweepstakes_id = holiday_2026. Add the confirmation message, a three-day delay, an audience path on email subscription state, and the bonus-entry message. Set re-eligibility (never, or after 24 hours for daily entries) and an exit criterion. Launch it.

Step 3. Send the entry from your backend

POST https://rest.iad-01.braze.com/users/track
Authorization: Bearer <REST API key>
Content-Type: application/json

{
  "attributes": [{
    "external_id": "c_20931",
    "email": "ana@example.com",
    "first_name": "Ana",
    "home_zip": "94110",
    "email_subscribe": "opted_in"
  }],
  "events": [{
    "external_id": "c_20931",
    "name": "sweepstakes_entered",
    "time": "2026-11-14T16:05:00Z",
    "properties": {
      "sweepstakes_id": "holiday_2026",
      "entry_id": "ent_55120",
      "opt_in": true,
      "source": "instagram_ad"
    }
  }]
}

-> 201 { "attributes_processed": 1, "events_processed": 1, "message": "success" }

Attributes and event names that do not exist yet are created on first use. Only set email_subscribe to opted_in when the box was checked; otherwise leave it alone so you do not overwrite an existing preference. If entrants have no account and you would rather not mint IDs, Braze can also identify users by email or by a user alias in the same endpoint.

Step 4. Personalize from the event

Hi {{${first_name} | default: 'there'}},

You're entered in the {{canvas_entry_properties.${sweepstakes_id} | replace: '_', ' ' | capitalize}} sweepstakes.
{% if canvas_entry_properties.${opt_in} == true %}
  Come back tomorrow for a bonus entry.
{% endif %}

canvas_entry_properties exposes the properties of the event that started the Canvas, for every step of it. The rest comes from the profile.

WHAT YOU BUILD BEFORE THE FIRST ENTRYSFMC1sendable DE2installed package3contact key plan4API Event source5journey + emails6re-entry + activate6 steps | schema designed up front | entry stored as a rowBraze1REST API key2Canvas, event entry3subscription state3 steps | schema created on first use | entry stored on the person
What has to exist before the first entry can enter a journey. Hover or tap any step.

4. Side by side

SFMCBraze
What the backend calls/v2/token, then /interaction/v1/events/users/track
Where the entry landsA row in Sweepstakes_EntriesAn event on the user profile
SchemaDesigned up front: fields, types, lengths, keyCreated on first use; manage with blocklists and naming rules
TriggerAPI Event entry source bound to one data extensionAction-based entry on a custom event
PersonalizationJourney Data or AMPscript reading the rowLiquid reading the profile and canvas_entry_properties
Repeat entriesRe-entry setting plus a primary key that allows duplicatesRe-eligibility setting; every entry is another event
ConsentSubscriber status, publication lists, send classificationSubscription state and subscription groups on the profile
Reuse laterSQL query activity joining tables on a scheduleSegment filter on the event and its properties
Typical failureJourney not active: row written, nobody entersEvent name typo: event recorded, Canvas never fires

Neither path is hard once it is set up. The difference is what you have built when you are done. In SFMC you have a table that exists because this campaign exists. In Braze you have a fact about a person that any future campaign can use.

5. After the launch: using the entry again

A week later, someone asks a normal question: which entrants bought something after entering? This is where the two models really diverge.

SFMC: join tables on a schedule

-- Automation Studio, SQL Query activity, nightly
-- Target: Sweepstakes_Entrants_Who_Bought (overwrite)
SELECT e.ContactKey, e.EmailAddress, COUNT(e.EntryId) AS Entries
FROM Sweepstakes_Entries e
JOIN Orders_Nightly_DE o ON o.ContactKey = e.ContactKey
WHERE e.SweepstakesId = 'holiday_2026'
  AND o.OrderDate >= e.EnteredAt
GROUP BY e.ContactKey, e.EmailAddress

Plus a target data extension, an automation to run it nightly, and the knowledge that the answer is as fresh as last night's run. Next season's sweepstakes gets a new data extension, and this query gets copied and edited.

Braze: a segment

Segment: Holiday entrants who bought
  Custom event  sweepstakes_entered
    property    sweepstakes_id = holiday_2026
    performed   at least 1 time in the last 30 days
  AND
  Purchased     any product in the last 30 days

No new table, no schedule, and it updates as events arrive. Next season's sweepstakes sends the same event with a different sweepstakes_id.

A ROW IN A TABLEA FACT ON A PERSONEntryIdContactKeySweepsEnteredAtent_55120c_20931holiday_2611-14ent_55121c_31877holiday_2611-14ent_55122c_20931holiday_2611-15ent_55123c_40112holiday_2611-15Sweepstakes_EntriesSpring_Sweeps_2027_DEContest_Entries_Final_v2Orders_Nightly_DEexternal_id: c_20931 Ana ana@example.com2026-11-14 sweepstakes_enteredholiday_20262026-11-15 sweepstakes_enteredholiday_2026 (bonus)2026-11-20 email_clickeddaily bonus entry2026-11-28 purchaseboot_412 $1292027-03-02 sweepstakes_enteredspring_2027
Where the entry ends up. Hover or tap the rows, the tables and the events.

6. Gotchas on each side

SFMC

  • Use a stable ID as ContactKey, not the email address. You cannot change a contact key later, and All Contacts is what you are billed on.
  • Activate the right version. Editing an active journey creates a new draft version; events go to whatever version is active.
  • Match the schema exactly. Send the exact field names, respect the lengths, and use consistent boolean and date formats.
  • Set retention on the entry data extension, or it quietly becomes a permanent copy of every entrant's PII.
  • Cache the token. Requesting a new one per entry is slow and can hit limits during a launch spike.

Braze

  • Name events like facts (sweepstakes_entered), keep one name across campaigns, and put the campaign in a property.
  • Watch data points. Attribute updates and custom events count toward your contract; do not resend unchanged attributes on every entry.
  • Batch during spikes. /users/track accepts up to 75 events, attributes and purchases each per request.
  • Do not overwrite consent. Only send email_subscribe when the person actually opted in.
  • Prefer the action-based entry over the API-triggered Canvas endpoint. The event can start this Canvas and every other use of the entry; an API trigger only starts this one.

7. What this sets up

Strip away the UI and the two launches differ in one way. SFMC asks you to design a table, write a row into it and point a journey at the table. Braze asks you to state a fact about a person and let anything that cares about that fact react to it.

Data extensions made sense when the email platform was the database: nightly files, batch sends, one table per use case. They are the reason SFMC programs accumulate hundreds of tables nobody owns, SQL activities that join them back together, and journeys that are only as fresh as the last import. Events and profiles are how modern platforms, warehouses and event-driven architectures already work. In a follow-up article I will make that case directly: why sending communications from events is replacing data extensions, and how to migrate an SFMC program that is built on them.

Related: Object Oriented Marketing, Marketing Eventing, AMPscript 101 and Liquid 101.

Sources

IDs, keys and payload values are illustrative. Sweepstakes are regulated; have counsel review your Official Rules and consent language.