> ## Documentation Index
> Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Migrate from Salesforce Marketing Cloud

> Map SFMC journeys, data extensions, and sends to Courier, with a phased plan.

export const Endpoint = ({method, path, name, href, children, bare}) => {
  const verb = String(method || "").toUpperCase();
  const title = verb + " " + path;
  const label = children || name || path;
  if (bare) {
    return href ? <a href={href}><code>{title}</code></a> : <code>{title}</code>;
  }
  if (!href) {
    return <span className="cx-endpoint" data-method={verb} title={title}>
        <span className="cx-endpoint-label">{label}</span>
        <span className="cx-endpoint-method">{verb}</span>
      </span>;
  }
  return <a className="cx-endpoint" data-method={verb} href={href} title={title}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">{verb}</span>
    </a>;
};

export const Guide = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="guide" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">GUIDE</span>
    </a>;
};

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

Plan a migration from Salesforce Marketing Cloud Engagement (SFMC) to Courier.

Most teams land on the same split. Salesforce keeps the customer data, Courier does the sending. Engineers, marketers, and AI agents build and send messages in Courier from data synced out of Salesforce.

## Map Salesforce Marketing Cloud concepts to Courier

| Salesforce Marketing Cloud                                                                                                                              | Courier                                                                                |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| [Journey Builder](https://developer.salesforce.com/docs/marketing/marketing-cloud/guide/journey-builder-api-overview.html)                              | <Doc href="/docs/journeys/overview">Journeys</Doc>                                          |
| Automation Studio (one-time and scheduled sends)                                                                                                        | <Doc href="/docs/broadcasts/overview">Broadcasts</Doc>                                      |
| Automation Studio (recurring sends)                                                                                                                     | Your scheduler + <Doc href="/docs/send/overview">send to a list or audience</Doc>           |
| Automation Studio (SQL queries, imports)                                                                                                                | Stays in your data stack. Sync results to Courier                                      |
| Email Studio / Content Builder                                                                                                                          | <Doc href="/docs/design/templates/design-studio">Design Studio</Doc>                        |
| Data Extensions                                                                                                                                         | <Doc href="/docs/recipients/overview">User profiles</Doc> (nested JSON)                     |
| Contact Builder / All Contacts                                                                                                                          | <Doc href="/docs/recipients/overview#the-profile-object">Users</Doc>                        |
| Filtered Data Extensions / segments                                                                                                                     | <Doc href="/docs/recipients/lists-and-audiences/audiences">Audiences</Doc>                  |
| [Triggered Sends / Transactional Messaging API](https://developer.salesforce.com/docs/marketing/marketing-cloud/guide/transactional-messaging-api.html) | <Doc href="/docs/send/overview">Send API</Doc>                                              |
| [API Event entry sources](https://developer.salesforce.com/docs/marketing/marketing-cloud/guide/journey-builder-api-overview.html)                      | <Doc href="/docs/journeys/invoke">Journey triggers</Doc>: API, webhook, Segment, audience   |
| [AMPscript](https://developer.salesforce.com/docs/marketing/marketing-cloud/guide/ampscript.html) / SSJS personalization                                | <Doc href="/docs/design/templates/variables">Handlebars variables</Doc> + `data` on send    |
| Subscription Center / publication lists                                                                                                                 | <Doc href="/docs/recipients/preferences/overview">Preferences</Doc>                         |
| MobileConnect / MobilePush (SMS and push)                                                                                                               | SMS and push channels through <Doc href="/docs/integrations/overview">your providers</Doc>  |
| MobilePush inbox / in-app messages                                                                                                                      | <Doc href="/docs/in-app/overview">Inbox</Doc>                                               |
| Sender Authentication Package (SAP)                                                                                                                     | Domain configuration with your <Doc href="/docs/integrations/overview">email provider</Doc> |
| Installed packages (OAuth 2.0 client credentials)                                                                                                       | <Doc href="/docs/reference/api-overview#authentication">API keys</Doc>                      |

### Journey Builder and Journeys

Journey Builder runs multi-step campaigns from entry sources. A contact lands in a Data Extension, fires an API event, or matches an audience. From there it moves through waits, decision splits, and sends.

Courier <Doc href="/docs/journeys/overview">Journeys</Doc> fill the same role. A journey starts from a <Doc href="/docs/journeys/invoke">trigger</Doc>: API invoke, inbound webhook, Segment event, or audience membership.

| Journey Builder activity              | Courier equivalent                                                                                                                  |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Email / SMS / push activity           | <Doc href="/docs/journeys/nodes/send">Send node</Doc> (references a template)                                                            |
| Wait activity                         | <Doc href="/docs/journeys/nodes/delay">Delay node</Doc>                                                                                  |
| Decision split                        | <Doc href="/docs/journeys/nodes/branch">Branch node</Doc>                                                                                |
| Einstein STO / engagement splits      | <Doc href="/docs/journeys/experiments">Experiments</Doc> on send nodes                                                                   |
| Journey exit criteria                 | <Doc href="/docs/journeys/nodes/cancel">Cancel node</Doc> + <Doc href="/docs/journeys/invoke">cancellation API</Doc>                          |
| Update contact activity               | <Endpoint method="PATCH" path="/profiles/{user_id}" name="Update a Profile" href="/docs/api-reference/user-profiles/update-a-profile" /> |
| Custom activity (fetch external data) | <Doc href="/docs/journeys/nodes/fetch-data">Fetch data node</Doc>                                                                        |

Two Courier nodes Journey Builder handles differently:

* **<Doc href="/docs/journeys/nodes/throttle">Throttle nodes</Doc>** cap how many times a user (or all users globally) can pass a point in a journey within a time window. SFMC has no built-in send-collision control, so teams build exclusion logic by hand across journeys. A throttle node expresses "max 3 marketing messages per user per 24 hours" directly in the workflow.
* **<Doc href="/docs/journeys/nodes/batch">Batch</Doc> and <Doc href="/docs/journeys/nodes/digest">digest</Doc> nodes** collapse many events into one message, which in SFMC requires SQL queries and scheduled automations.

### Automation Studio

Automation Studio does three jobs. Each migrates somewhere different.

**One-time and scheduled sends** become <Doc href="/docs/broadcasts/overview">Broadcasts</Doc>. Pick a template and a list or audience, then send now or schedule a date, time, and timezone. Scheduled broadcasts can be rescheduled or canceled until they fire.

**Recurring sends** (a daily or weekly automation that sends to a refreshed Data Extension) have no direct equivalent, because broadcasts don't repeat. Run the schedule where your other cron jobs live and call the <Doc href="/docs/send/overview">send API</Doc> against a list or audience. Audience membership updates automatically as profiles change, so the "refresh the Data Extension, then send" two-step collapses into one API call.

**Data workflows** (SQL query activities, file imports, data extracts) don't move to Courier. Courier is not an ETL tool. Run those transformations in your data warehouse, in Salesforce, or in your application. Sync the results to Courier as user profile attributes or audience memberships. The SQL that lived in Automation Studio moves into version-controlled code in your own stack.

### Email Studio, Content Builder, and Design Studio

Templates move to <Doc href="/docs/design/templates/design-studio">Design Studio</Doc>. A Courier template holds content for every channel (email, SMS, push, in-app, chat) in one resource. Build it with drag-and-drop blocks, or define it as <Doc href="/docs/design/elemental/overview">Elemental</Doc> JSON.

For one-time campaign sends that lived in Email Studio, use <Doc href="/docs/broadcasts/overview">Broadcasts</Doc> with the template and an audience.

### Data Extensions and user profiles

Data Extensions are relational tables. Courier <Doc href="/docs/recipients/overview">user profiles</Doc> are JSON documents keyed by `user_id`. This is the biggest shift in the migration.

Your **sendable Data Extension** (the one keyed by subscriber key with email, phone, and personalization fields) becomes the Courier user profile. Profiles accept nested JSON, so attributes like plan tier, care team, or order history need no schema migration.

**Relational Data Extensions** (lookup tables you join with SQL) stay in your database. Flatten what a message needs onto the profile at sync time, or pass it in the `data` field at send time. Data that changes per event belongs in `data`. Data that describes the person belongs on the profile.

Load users in bulk with the <Guide href="/docs/guides/send-in-bulk">bulk API</Guide> or create them inline: sending to an unknown `user_id` with profile data creates the user.

### Keeping Salesforce as the system of record

You don't migrate off Salesforce, only off Marketing Cloud's sending layer. Contacts, deals, and consent records stay in Salesforce CRM. What SFMC did with Marketing Cloud Connect, you do with a sync process you control:

1. **Outbound from Salesforce**: platform events, Change Data Capture, or a scheduled export push contact changes to your backend.
2. **Into Courier**: your backend upserts profiles through the <Endpoint method="PATCH" path="/profiles/{user_id}" name="Update a Profile" href="/docs/api-reference/user-profiles/update-a-profile">users API</Endpoint> or bulk jobs, and audience membership recalculates automatically from profile attributes.
3. **At send time**: your application triggers sends and journeys with event data. Courier joins it with the synced profile.

The sync is one-directional and small. Courier needs identifiers, channel addresses, and the attributes you segment or personalize on, not your whole CRM.

### Triggered sends and the Send API

SFMC's Triggered Sends and Transactional Messaging API map to the Courier <Doc href="/docs/send/overview">send API</Doc>. One request sends to a user across any configured channel. Courier handles routing, provider failover, and delivery tracking. No separate transactional subsystem to configure. Every send goes through the same pipeline.

### Subscription Center and preferences

SFMC publication lists and the Subscription Center manage opt-outs, mostly for email. Courier <Doc href="/docs/recipients/preferences/overview">Preferences</Doc> manage opt-in and opt-out per topic and per channel. Courier enforces them at send time.

You get a <Guide href="/docs/guides/build-a-preference-center#hosted-page">hosted preference page</Guide>, or <Guide href="/docs/guides/build-a-preference-center#embedded-component">embeddable components</Guide> to build the preference center into your product. Map each publication list to a preference topic during migration, and carry unsubscribes over before the first send.

### AMPscript and personalization

AMPscript and SSJS blocks become <Doc href="/docs/design/templates/variables">Handlebars variables</Doc> plus data you pass on the send call. `Lookup()` and `LookupRows()` patterns invert. A template used to reach into a Data Extension at render time. Now you fetch the data first, or use a <Doc href="/docs/journeys/nodes/fetch-data">fetch data node</Doc> mid-journey, then pass it in `data`. Templates render from what you give them, which makes sends reproducible and testable.

### Authentication

SFMC authenticates through installed packages: OAuth 2.0 client credentials against a tenant-specific subdomain, with scoped tokens that expire. Courier uses <Doc href="/docs/reference/api-overview#authentication">API key authentication</Doc>, a bearer token per workspace, with separate keys for test and production. Server-side calls use the key directly. Client-side surfaces like in-app inbox use short-lived <Doc href="/docs/in-app/authenticate-users">JWTs</Doc> scoped to a user.

## Plan the migration

1. **Inventory what actually sends.** Export your active journeys, triggered sends, and automations. Most SFMC accounts carry years of dead journeys. Migrate the live ones.
2. **Stand up the data sync.** Salesforce to your backend to Courier profiles. Validate with a test audience before moving anything user-facing.
3. **Recreate templates in Design Studio.** Start from the highest-volume sends. Move AMPscript logic into send-time `data`.
4. **Map publication lists to preference topics** and import unsubscribes first.
5. **Rebuild journeys, one at a time.** Run the Courier journey in parallel against a test audience and compare output. Then cut the entry source over and pause the SFMC journey.
6. **Point triggered sends at the send API.** They cut over cleanly, because they are already API-driven in SFMC.
7. **Decommission by watching send logs**, not the calendar. When an SFMC journey has sent nothing in 30 days and its Courier replacement is live, retire it.

## Migrate with an AI agent

If you're running the migration with Claude Code, Cursor, or another coding agent, two things help:

* **<Doc href="/docs/resources/mcp">Courier's MCP server</Doc>** gives your agent direct access to your workspace. It can create templates, build journeys, upsert users, and inspect send logs as it works through the plan above.
* The concept-mapping table at the top of this page is the translation layer. An agent holding an SFMC journey export and that table can propose the equivalent Courier journey. The <Doc href="/docs/journeys/build">journeys API</Doc> lets it build the result programmatically.

A workable prompt: export the journey definition from SFMC's REST API (`/interaction/v1/interactions`), then hand it to your agent with this page. Ask for the equivalent Courier journey, plus the profile fields the sync has to provide.

## FAQ

<AccordionGroup>
  <Accordion title="Can I keep Salesforce as my system of record?">
    Salesforce should stay your system of record. Contacts, deals, and consent records stay in Salesforce CRM. A sync you control (platform events, Change Data Capture, or scheduled exports) pushes identifiers, channel addresses, and segmentation attributes into Courier as <Doc href="/docs/recipients/overview">user profiles</Doc>. Courier replaces Marketing Cloud's sending layer, not your CRM.
  </Accordion>

  <Accordion title="What replaces Salesforce Journey Builder in Courier?">
    <Doc href="/docs/journeys/overview">Journeys</Doc>. Entry sources become <Doc href="/docs/journeys/invoke">triggers</Doc>: API invoke, inbound webhook, Segment event, or audience membership. Journey Builder activities map to nodes. Waits become <Doc href="/docs/journeys/nodes/delay">delay</Doc>, decision splits become <Doc href="/docs/journeys/nodes/branch">branch</Doc>, and sends become <Doc href="/docs/journeys/nodes/send">send nodes</Doc>. Courier adds <Doc href="/docs/journeys/nodes/throttle">throttle</Doc> and <Doc href="/docs/journeys/nodes/digest">digest</Doc> nodes that Journey Builder has no equivalent for.
  </Accordion>

  <Accordion title="What happens to my Data Extensions?">
    Your sendable Data Extension becomes Courier user profiles: JSON documents keyed by `user_id` that accept nested attributes without a schema. Relational Data Extensions stay in your database. Flatten what a message needs onto the profile at sync time, or pass it in the `data` field at send time.
  </Accordion>

  <Accordion title="Does Courier support AMPscript?">
    Personalization uses <Doc href="/docs/design/templates/variables">Handlebars variables</Doc> in templates plus data you pass on the send call. AMPscript patterns that look up data at render time invert in Courier. Fetch the data before you send, or use a <Doc href="/docs/journeys/nodes/fetch-data">fetch data node</Doc> mid-journey, then pass the result in `data`.
  </Accordion>

  <Accordion title="What parts of Salesforce Marketing Cloud does Courier not replace?">
    Landing pages (CloudPages), ad audience activation (Advertising Studio), marketing attribution, and Automation Studio's data-transformation work (SQL query activities, imports, extracts). Those stay in Salesforce or elsewhere in your stack. Courier replaces message delivery and orchestration: journeys, triggered sends, campaigns, templates, and preferences.
  </Accordion>
</AccordionGroup>
