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

# White-label email

> Send every merchant's email in their own logo and colors from one journey and one template, with a Look up record step.

If you send email on behalf of many merchants, each one wants their customers
to see **their** brand. Instead of one template per merchant, keep each
merchant's branding as a record in your CDP and let the journey load it: a
**Look up record** step finds the right record for each run, and the email's
colors, logo and copy read from it.

A merchant with no record gets your default branding, so a new merchant never
blocks a send.

> [!TIP]
>
> Look up record loads any custom object, not just a brand. The same steps
> send an order total, a plan name or a due date the triggering event doesn't
> carry.

## 1. Store each merchant's brand

Create a custom object type for the branding, for example `merchant_brand`,
and one record per merchant. Use the merchant's ID as the record's
**external ID**, and give it the fields your email needs:

| Field | Example |
| - | - |
| `name` | `Marea` |
| `logo_url` | `https://cdn.example.com/marea/logo.png` |
| `primary_color` | `#1D5FD1` |

Load them like any other data: with the API
([`POST /api/v1/cdp/custom-objects/types`](/api-reference/cdp-custom-objects/create-object-type),
then [`POST /api/v1/cdp/custom-objects`](/api-reference/cdp-custom-objects/upsert-object)),
an import, or a sync. A color is a hex (`#1D5FD1`), an `rgb()` or `hsl()` with
plain numbers, or a CSS color name. Anything else is treated as empty.

If your journeys start from a person rather than an event that names the
merchant, also link people to merchants and merchants to their brand. See
[Relationship types](/relationship-types.md).

## 2. Add a Look up record step

In the journey, add **Look up record** right before the email step, and set:

* **Record type**: `Merchant Brand`.
* **Save as**: the name later steps use, for example `brand`. It becomes
  `{{brand.logo_url}}`, `{{brand.primary_color}}` and so on.
* **How to find it**:
  * **By an ID this run carries**: insert the variable that holds the
    merchant's ID, such as `event.merchant_id` on the event that started the
    journey, a person attribute, or a field of a record an earlier step
    loaded.
  * **Linked to the person**: pick how the person is linked, up to three
    hops (person → merchant → merchant brand).
* **Fields to load**: tick every field the email uses (up to 30). Only these
  are available to later steps.
* **If several match** (linked to the person): pick the field that decides
  which record wins, and whether the highest or lowest value wins. Without
  it, several matches load nothing.

The record is read when the run reaches the step, so place it right before the
step that uses it, not before a long wait.

## 3. Bind the email to the record

Open the email template in the editor:

* **Colors**: next to any color (text, heading, button, divider, background),
  choose `{ }` (*Use a variable for…*) and type `brand.primary_color`. The
  swatches you pick become the fallback, used when the value is empty or isn't
  a color.
* **Logo and images**: on an image, choose `{ }` and type `brand.logo_url`.
  The image you already had becomes the **Fallback image URL**. Always keep a
  fallback image: without one, a merchant with no logo gets an empty image.
* **Copy**: use the record anywhere you write text, for example
  `Your order with {{brand.name | default: 'us'}}` in the subject.

In the journey, the email step's preview runs the lookup on a real triggering
event, so you see the email in that merchant's brand. The editor itself shows
the fallback colors. The step's variables are split into **Content** (text)
and **Style** (colors and images).

## What happens at send time

* **The run always continues.** If no record is found, the step records **No
  record found**, the fields are empty and the email uses its fallbacks.
* **Unsafe values are removed.** Before an email goes out, Boom checks the
  values that came from your data. A value that would add a script, an event
  handler or a `javascript:` link is removed.
* **Each run shows what it found.** The run's timeline says **Record found:
  Marea**, or why nothing was found (no match, an empty ID, several matches
  and no rule).

## What publishing checks

Every `brand.<field>` the journey reads, **including inside its email
templates**, must be loaded by a Look up record step saved as `brand` that
runs before it. If the email reads `brand.primary_color` and the step doesn't
load it, publishing is refused and names the field to add.

## Other channels and uses

Saved records work in emails, WhatsApp, SMS, Instagram and Messenger messages,
HTTP requests and Dispatch event steps. Decision and Case steps can't read
`brand.*` directly; to branch on whether a record was found, use the step's
**Found** output.

## With the API and MCP

Journeys built over the API or MCP use the same step (`LOAD_OBJECT`, with
`objectType`, `saveAs`, `lookup` and `attributes`) and the same publish checks.
See [Journeys](/journeys.md) for the node reference and [Use Boom from
MCP](/use-mcp.md) to connect an AI agent.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.