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

# Customizing the Checkout Page (Branding, Colors, Logos)

> How to brand the Waffo checkout page: where Customization lives in the Portal, every color and size you can set, which field controls font size at order create, how order parameters override Portal settings, MID vs SubMID configuration, multiple logos and logo IDs, the live preview and its limits, and who on your team can save changes.

This page covers the look and feel of the Waffo-hosted checkout page — colors,
fonts, logos and merchant name. The *order* in which payment methods appear is
a different setting; that is covered by the Checkout Payment Method Display
Rules page. What the page does across the order lifecycle (reopened links,
processing states, result redirects) is covered by the Checkout Page Lifecycle
& Receipt page.

## Where do I configure how the Waffo checkout looks?

In the Merchant Portal, open **Checkout → Customization**. The page has three
tabs and a live preview beside them:

| Tab | What it holds |
| - | - |
| **Features** | Merchant logo upload and the logo list |
| **Style** | Theme and colors, text information (header layout and font sizes), and — where enabled for your account — amount display |
| **Cashier Ranking** | The order payment methods appear in, per country, plus the group-by-country switch |

Changes across all three tabs are staged locally and committed together when
you press **Save**.

## Which colors and sizes can I actually change?

The Style tab exposes four preset themes (**Default**, **Yellow**, **Dark**,
**Green**) as one-click starting points, then these individual controls:

| Control | What it paints | Range |
| - | - | - |
| `colorPrimary` | Primary/brand color — buttons and accents | Any color |
| `colorBackground` | Page background | Any color |
| `colorCard` | Card background | Any color |
| `colorText` | Primary text | Any color |
| `colorTextSecondary` | Secondary text | Any color |
| `colorTextTertiary` | Tertiary text | Any color |
| `colorDanger` | Error text and error states | Any color |
| `colorInfo` | Information/notice blocks | Any color |
| `colorBorder` | Borders and dividers | Any color |
| `fontSizeBase` | Base font size for the page | 12–24 px |
| `buttonRadius` | Corner radius of buttons | 0 px and up |

Under **Text Information** you additionally choose whether the header leads
with the **Order Description** or the **Merchant Name**, and set a font size
for each (14–24 px).

An **Amount Display** section — which currency is shown as the primary amount,
and the primary/secondary amount font sizes — is only present for accounts it
has been enabled for. If you do not see it, it is not enabled for your account.

Picking a preset theme replaces the colors and sizes but keeps your Text
Information and Amount Display choices.

## Which field controls the font size on the checkout page when I create an order?

`paymentInfo.cashierAppearance`. It is a **JSON string** carrying a `variables`
object, and the base font size is the `fontSizeBase` key inside it:

```json theme={null}
{
  "variables": {
    "fontSizeBase": "18px",
    "colorPrimary": "#2749F8",
    "buttonRadius": "24px",
    "headerDisplay": {
      "primaryDisplay": "orderDesc",
      "orderDescFontSize": "18px",
      "merchantNameFontSize": "14px"
    }
  }
}
```

The keys are exactly the ones listed in the table above, and sizes carry their
`px` unit as strings. Two behaviours worth knowing:

* The value must be **valid JSON**. A malformed string is discarded and the
  order is still created — it will simply render with your Portal
  configuration instead, with no error to tell you why.
* Only the keys you send are applied. Everything you omit falls back to your
  Portal configuration, then to the system default.

## My Portal styling is not showing on the checkout page. What wins?

Styling is resolved in this order, highest first:

| Priority | Source |
| - | - |
| 1 | Values sent on the order (`paymentInfo.cashierAppearance`, and the brand fields below) |
| 2 | Your Portal **Checkout → Customization** configuration |
| 3 | Waffo system defaults |

The merge is **per key**, not all-or-nothing: a `cashierAppearance` that sets
only `colorPrimary` keeps your Portal values for every other key. So if a
single color looks wrong while the rest looks right, check what your
integration is sending on the order before checking the Portal.

The same precedence applies to the two brand fields:

| Field | Effect |
| - | - |
| `brandInfo.cashierDisplayName` | Overrides the configured merchant display name for that checkout session. Max 128 characters |
| `brandInfo.cashierLogoUrl` | Overrides the configured logo for that checkout session. Max 512 characters |

## I saved a new style. Which orders does it affect?

The configuration is read **when a checkout page is rendered**, not frozen at
order creation. In practice:

* A checkout page a customer already has open is unaffected — it keeps
  rendering what it loaded with until it is reloaded.
* Any checkout page opened after the save picks up the new configuration,
  including pages for orders that were created before you saved.

There is no per-order snapshot of your Portal styling. If a specific order must
keep a specific look regardless of later Portal edits, send the styling on the
order itself.

## Can each of my SubMIDs have its own look?

Yes. The Customization page has a **Configuration Scope** card listing your
SubMIDs, controlled by one switch:

| `Apply MID config to all SubMIDs` | Behavior |
| - | - |
| **On** | The SubMID list is hidden; you maintain one configuration |
| **Off** | Each SubMID is listed with a status tag and its own actions |

With the switch off, every SubMID row shows either **Using MID config** or
**Customized**. **Edit** opens that SubMID in the same three tabs — you are
editing that SubMID, not the MID, and the header tells you so. **Reset** (only
offered on a customized SubMID, and behind a confirmation) drops that SubMID's
own logos and style so it goes back to Using MID config.

Two details that surprise people:

* Opening a SubMID that is on **Using MID config** shows you the MID's style
  as a starting point but **not** the MID's logos. If you change nothing, the
  SubMID stays on Using MID config — it is not silently converted into a
  customized one.
* Only SubMIDs that have payment methods available are listed.

## How do I upload more than one logo, and where does the logo ID come from?

Upload logos in the **Features** tab. Rules the page enforces:

| Rule | Detail |
| - | - |
| Formats | **PNG, JPG, JPEG** only — SVG is rejected |
| Recommended size | 40 × 40 px |
| Default logo | The first logo you upload becomes the default automatically; **Set as default** moves it to any other logo |
| Deleting | Deleting the default promotes the first remaining logo to default |
| Logo ID | Assigned by Waffo **on save**, not at upload time |

The ID format is stable and predictable:

| Level | Format | Examples |
| - | - | - |
| MID | `logo_M{n}` | `logo_M1`, `logo_M2` |
| SubMID | `logo_S{last 3 digits of the SubMID}_{n}` | `logo_S417_1`, `logo_S417_2` |

IDs are unique within your account, and once a logo has been saved its ID is
never reused.

## I have three logos but my newest one is logo\_M5. Is that a bug?

No. The sequence number is allocated from the highest number ever used on that
MID or SubMID, and deleted logos keep their number. Delete `logo_M2` and
`logo_M3`, upload a new logo, and it becomes `logo_M4` — the gaps are
permanent by design, so an ID you hard-coded in your integration can never
start pointing at a different image.

## Can I pass a logo directly on the order instead of using a logo ID?

Yes, and both go in the **same field** — `brandInfo.cashierLogoUrl`. It is
routed by prefix:

| Value starts with | Treated as | Behavior |
| - | - | - |
| `http://` or `https://` | A logo **URL** | That image is used for this checkout session |
| `logo_` | A logo **ID** | The matching uploaded logo is used |
| Anything else | Invalid | Silently dropped; the order is still created |

A logo URL takes precedence over a logo ID, so passing a URL overrides your
Portal logo list entirely for that session (your Portal *style* configuration
is still applied). Fallbacks when no usable logo is found:

* An ID that does not exist, or belongs to a deleted logo → the **default**
  logo is used.
* No logo passed at all → the **default** logo is used.
* A URL that does not pass validation → dropped, then the same fallbacks apply.
* No logo configured anywhere → no logo is displayed.

## What does the header show if I have only a logo, or only a name?

Four combinations, all of them supported:

| Logo | Merchant display name | Header shows |
| - | - | - |
| Yes | Yes | Logo on the left, name beside it |
| Yes | No | Logo only |
| No | Yes | Name only |
| No | No | No merchant identity block — the page leads with the amount |

The name shown is always the **cashier display name** (from the order, from
your SubMID, or from your MID, in that order). Your KYB-registered legal name
is never used here. See the Checkout Page Lifecycle & Receipt page for the one
exception involving disclosure footnotes.

## How accurate is the live preview?

The preview renders a real checkout page next to the form, so colors, sizes,
logo, header layout and payment-method ranking all update as you edit. A
Mobile / Desktop toggle sits under it, the preview follows the country you have
selected on the **Cashier Ranking** tab, and it renders in your Portal
interface language.

Two limits are worth knowing before you report a difference as a bug:

* The preview cannot know **per-order availability**. Real checkout pages gray
  out or drop a payment method that is temporarily unavailable, or that does
  not apply to a specific order; the preview does not, so a real buyer may see
  slightly fewer options.
* The preview and the real checkout share the **same cap on how many payment
  methods can be shown on one flat list**. If you turn off group-by-country and
  your deduplicated list exceeds that cap, both the preview and the real page
  fall back to country grouping — the Portal warns you with the exact counts
  when you cross it.

## Who on my team can change these settings?

Saving is gated by a single checkout-customization edit permission. An account
without it gets the whole page **read-only**: preset buttons, color pickers,
sliders, switches, drag handles and upload are all disabled, there is no Save
button, and the SubMID list offers **Detail** instead of **Edit**. The page
itself remains viewable.

By role, as the Portal role set is defined:

| Role | Customization page |
| - | - |
| Super Admin | View and save |
| Admin | View and save |
| General | View only |
| Read-only | View only |
| Developer | View only |
| Dispute Manager | No access |

## Do I need Waffo to approve a customization change?

No. Saving is immediate and self-serve — there is no review step. If a save is
rejected, it is a validation problem on the values you entered, not an
approval.

***

Still not rendering what you expect? [Contact support](mailto:support@waffo.com)
with the order ID and, if you send styling on the order, the exact
`cashierAppearance` string you sent — the most common cause is an order-level
value quietly overriding the Portal.


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