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

# Brands

> Sign on behalf of several brands from one account: save each brand's title, logo and colours once and select it per template or per submission.

## Overview

A **brand** is a named set of signing-page and email branding — header title, logo,
favicon, colours and the "Powered by" line — saved on your account. Accounts that send
documents for more than one brand (for example a firm that signs for both *Acme Legal* and
*Northwind Injury Law*) create one brand each and select it with `preferences.brand_id` on
a template or on a single submission, instead of repeating the branding keys everywhere.

* Brands are managed in **Settings → Brands** or through the API. Both need an
  **account admin** (the API returns `403` otherwise).
* A brand's `branding` accepts the same keys as a
  [custom domain's branding](/features/custom-domains#brand-each-domain):
  `display_title`, `logo_url`, `favicon_url`, `company_name`, `primary_button_color`,
  `header_color`, `show_branding`.
* Branding is looked up when the signing page or an email is rendered, not copied onto the
  submission — editing a brand changes it for every signer who has not finished yet.

## Manage Brands in Settings

**Settings → Brands** lists your brands by name, each with its ID (the value for
`brand_id`), a colour swatch and a summary of the keys it sets.

* **New brand** opens the brand editor. **Edit** and **Delete** act on one brand.
* The editor has fields for the brand name, header title, logo URL, favicon URL, company
  name, brand colour, header colour and the "Powered by SpitShake" line (same as account,
  show or hide). A live preview shows the signing-page header as the signing page will
  draw it.
* A field left blank falls through to the signing domain's branding, then the account's.

## Pick a Brand and Domain in the Template Builder

In the Template Builder, **Template Settings** has two pickers:

* **Brand**: *No brand* or one of your brands. It saves `preferences.brand_id`. A template
  that names a deleted brand shows it as *Brand #id (deleted)*.
* **Signing domain**: *Account default* (your primary custom domain, or the platform
  domain), the platform domain itself (saved as `"default"`), or one of your active custom
  domains. It saves `preferences.custom_domain`.

The same section's **Signing Experience** group sets the
[bottom navigation style](/guides/preferences#signing-behavior) (`signing_nav_style`).

## List Branding Options

`GET /api/branding_options` returns only the choices the pickers need: brand ids and names,
and your **active** custom domains. Unlike `/api/brands` and `/api/custom_domains` it is not
admin-only (it needs the `templates:read` scope), and it returns no branding values or DNS
details. Brands are ordered by name and domains by hostname.

<RequestExample>
  ```bash cURL theme={null}
  curl "https://spitshake.io/api/branding_options" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "brands": [
      { "id": 7, "name": "Acme Legal" },
      { "id": 8, "name": "Northwind Injury Law" }
    ],
    "custom_domains": [
      { "domain": "sign.example-firm.com", "primary": true }
    ]
  }
  ```
</ResponseExample>

## Create a Brand

`name` is required, at most 120 characters, and unique within the account
(case-insensitively). Leading and trailing spaces are removed before these checks. Only your
team sees the name. `branding` is optional.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://spitshake.io/api/brands" \
    -H "X-Auth-Token: YOUR_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Acme Legal",
      "branding": {
        "display_title": "Acme Legal",
        "logo_url": "https://cdn.example.com/acme/logo.png",
        "favicon_url": "https://cdn.example.com/acme/favicon.png",
        "company_name": "Acme Legal LLP",
        "primary_button_color": "#2f5d8a",
        "header_color": "#14213d",
        "show_branding": false
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "brand": {
      "id": 7,
      "name": "Acme Legal",
      "branding": {
        "display_title": "Acme Legal",
        "logo_url": "https://cdn.example.com/acme/logo.png",
        "favicon_url": "https://cdn.example.com/acme/favicon.png",
        "company_name": "Acme Legal LLP",
        "primary_button_color": "#2f5d8a",
        "header_color": "#14213d",
        "show_branding": false
      },
      "created_at": "2026-09-28T15:00:00Z",
      "updated_at": "2026-09-28T15:00:00Z"
    }
  }
  ```

  ```json 422 — Duplicate Name theme={null}
  {
    "error": "Name has already been taken"
  }
  ```

  ```json 422 — Invalid Branding theme={null}
  {
    "error": "Branding header_color must be a #rrggbb colour dark enough for white header text"
  }
  ```

  ```json 422 — Branding Not an Object theme={null}
  {
    "error": "branding must be an object"
  }
  ```
</ResponseExample>

### Branding keys

| Key | Type | Description |
| - | - | - |
| `display_title` | string | Header title and email title, shown verbatim. Also the first part of the browser-tab title. |
| `logo_url` | string | Logo beside the title and in emails. Must be an `http(s)` URL. |
| `favicon_url` | string | Browser-tab icon on the signing page. Must be an `http(s)` URL. Falls back to `logo_url`. |
| `company_name` | string | Logo alt text and email wordmark. Also the second part of the browser-tab title. |
| `primary_button_color` | string | Button colour. Also the header colour, darkened 20%, unless `header_color` is set, and the accent for field highlights, checkboxes and the signature window (darkened until white text reads on it). |
| `header_color` | string | Header bar colour, used verbatim — for brands whose header is not a shade of their button colour. Must be a `#rrggbb` dark enough for the header's white text. |
| `show_branding` | boolean | `false` hides the "Powered by SpitShake" line. |

Validation matches custom-domain branding: an unknown key (usually a typo), a non-string
value, a non-boolean `show_branding`, a `logo_url`/`favicon_url` that is not `http(s)`, or a
light or malformed `header_color` is rejected with `422`. A key sent as `null` or `""` is
dropped.

## List, Get, Update and Delete

<RequestExample>
  ```bash List theme={null}
  curl "https://spitshake.io/api/brands" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```

  ```bash Get theme={null}
  curl "https://spitshake.io/api/brands/7" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```

  ```bash Update theme={null}
  curl -X PUT "https://spitshake.io/api/brands/7" \
    -H "X-Auth-Token: YOUR_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Acme Legal",
      "branding": {
        "display_title": "Acme Legal",
        "logo_url": "https://cdn.example.com/acme/logo-2026.png",
        "primary_button_color": "#2f5d8a"
      }
    }'
  ```

  ```bash Delete theme={null}
  curl -X DELETE "https://spitshake.io/api/brands/7" \
    -H "X-Auth-Token: YOUR_API_TOKEN"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 — List theme={null}
  {
    "brands": [
      {
        "id": 7,
        "name": "Acme Legal",
        "branding": { "display_title": "Acme Legal", "primary_button_color": "#2f5d8a" },
        "created_at": "2026-09-28T15:00:00Z",
        "updated_at": "2026-09-28T15:10:00Z"
      },
      {
        "id": 8,
        "name": "Northwind Injury Law",
        "branding": { "display_title": "Northwind Injury Law", "primary_button_color": "#7a1f1f" },
        "created_at": "2026-09-28T15:05:00Z",
        "updated_at": "2026-09-28T15:05:00Z"
      }
    ]
  }
  ```

  ```json 200 — Get / Update theme={null}
  {
    "brand": {
      "id": 7,
      "name": "Acme Legal",
      "branding": {
        "display_title": "Acme Legal",
        "logo_url": "https://cdn.example.com/acme/logo-2026.png",
        "primary_button_color": "#2f5d8a"
      },
      "created_at": "2026-09-28T15:00:00Z",
      "updated_at": "2026-09-28T15:10:00Z"
    }
  }
  ```

  ```json 200 — Delete theme={null}
  {
    "success": true
  }
  ```
</ResponseExample>

* The list is ordered by name. A brand of another account returns `404`.
* `PUT` **replaces** the whole `branding` object: keys you leave out are removed, and a key
  sent as `null` or `""` is removed too. Omit `branding` entirely to rename only.
* Deleting a brand does not touch templates or submissions that name it: their
  `brand_id` simply stops matching, and they fall back to their other layers (see
  [Precedence](#precedence)).

## Use a Brand on a Template or Submission

Set `preferences.brand_id` to the brand's `id`. On a template it applies to every
submission created from that template:

```json theme={null}
PUT /api/templates/tpl_7VQhP2tM9xA1kR8bN
{
  "preferences": {
    "quick_sign_mode": "confirmation_modal",
    "brand_id": 7
  }
}
```

<Warning>
  `PUT /api/templates/:id` replaces the template's whole `preferences` object. Send the
  template's existing preferences with `brand_id` added, not `brand_id` alone.
</Warning>

On a submission it applies to that submission only, and **replaces** the template's brand —
the two brands are never mixed:

```json theme={null}
POST /api/submissions
{
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "preferences": {
    "brand_id": 8,
    "custom_domain": "sign.example.com"
  },
  "submitters": [{ "role": "Client", "email": "client@example.com" }]
}
```

`brand_id` is not validated when you save it. An id that is not one of your account's
brands — mistyped, deleted, or belonging to another account — is ignored at render time.
On a submission it still counts as the submission choosing a brand, so the template's brand
does not apply either.

A brand only sets branding. It does not choose the link host: pair it with
[`preferences.custom_domain`](/features/custom-domains#choose-a-domain-per-template-or-submission)
if the brand also has its own domain.

## Precedence

Each branding key resolves independently; the first layer with a non-empty value wins:

| # | Layer | Applies when |
| - | - | - |
| 1 | Submission `preferences.<key>` | always |
| 2 | Submission's brand | the submission sets `brand_id` |
| 3 | Template `preferences.<key>` | always |
| 4 | Template's brand | the template sets `brand_id` and the submission does **not** |
| 5 | Sending [custom domain's `branding`](/features/custom-domains#brand-each-domain) | the submission is sent on a custom domain |
| 6 | Account `settings.<key>` | always |

So a brand outranks the domain's branding, and a key set directly in the template's or
submission's own preferences outranks the brand at that level. For example, a template
with `brand_id: 7` and `display_title: "Acme Legal Retainer"` shows that title with the
brand's logo and colours; a submission can still override any single key.

<Note>
  `header_color` and `favicon_url` are checked when rendered. A light or malformed
  `header_color` picked from template or submission preferences (or account settings) is ignored and the header
  falls back to `primary_button_color` darkened 20% — it does not fall through to a lower
  layer's `header_color`. A `favicon_url` that is not `http(s)` falls back to `logo_url`.
  Brands and domains reject such values when saved, so this only affects preferences.
</Note>

## Tab title and favicon

The signing page's browser tab uses the resolved branding of the submission, so a brand
or domain changes it along with the header.

* **Title:** `<display_title or template name> - <company_name>`. When no layer sets
  `company_name`, the account's white-label display name is used, then the account name,
  then "SpitShake". A part that is identical to the other is shown once. For example, a
  brand with `display_title: "Acme Legal"` and `company_name: "Acme Legal LLP"` gives
  **Acme Legal - Acme Legal LLP**.
* **Icon:** the resolved `favicon_url`, or the resolved `logo_url` when no layer sets a
  favicon. With neither, the page sets no icon of its own.


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