Skip to main content

Settings → Branding

The Branding page under Settings is the self-serve white-label console for your dashboard: upload a logo and favicon, pick primary and accent colors, set a dashboard name and support email, and point a custom domain at your Orbit dashboard. Everything on the page is cosmetic — it changes how your dashboard, sign-in screen, and branded surfaces look. It touches no sending, routing, or compliance posture. This guide walks each control on the page, the two API write paths behind it (org-level shortcut vs. per-subaccount override), the custom-domain CNAME flow, and how branding resolves for each host at render time.

What the console controls

Open Settings → Branding. The controls you need are an owner or admin role; members see the page read-blocked. The top card — Brand identity — carries: Logo and favicon accept PNG, JPEG, or WebP up to 2 MB — SVG and ICO are rejected (SVG can carry script markup, so the API refuses it at upload). Colors are 6-digit hex (#4F46E5); the form shows a live preview of the pair on the dashboard shell before you save, and a per-field Revert resets any single edited field to the last saved value. Reset to defaults at the bottom of the card clears all of it with a confirmation step. The page also hosts the help center theme card (a separate, public-safe subset of fields) and the branded calling card, which governs how your brand renders on carriers’ incoming-call screens — both are out of scope here.

Two write paths

Every change on this page persists through one of two endpoint pairs, depending on whose branding you’re setting:
  • Your own organizationPUT /api/v1/organization/branding. A shortcut for a tenant managing its own look; the dashboard console uses this. There’s no org id in the path — the caller’s organization is the target.
  • A subaccount you operatePUT /api/v1/subaccounts/{id}/branding. The reseller path: a parent org overrides branding for a child org it manages. A subaccount’s own admin can also call this with its own id.
Both accept the same body — any subset of logo_url, favicon_url, primary_color, accent_color (6-digit hex), dashboard_name (≤ 50 characters), support_email, terms_url, privacy_url — and both record the change in the audit log. Send null for a field to clear it; fields you omit keep their stored value. POST /api/v1/organization/branding/reset wipes the whole set back to platform defaults in one call, same as the console’s reset button. Which one you reach for:
  • You run one Orbit organization and want it in your brand → the org-level shortcut (/organization/branding), or simply the dashboard page.
  • You resell Orbit and brand each customer’s console differently → the per-subaccount path (/subaccounts/{id}/branding), usually from the subaccount onboarding flow. A subaccount that flips on inherit_branding_from_parent takes your parent branding wholesale instead — the subaccount–organization model covers how inheritance resolves.

Custom domain

The second card on the page puts the dashboard on your own hostname — app.acme.example instead of orbit.devotel.io. The flow is register → publish a CNAME → verify → automatic TLS:
  1. Register the hostname. Enter it in Custom domain (or call the org-level shortcut POST /api/v1/organization/domains; resellers use POST /api/v1/subaccounts/{id}/domains). The response — and every later read of the domain — carries the cname_target your DNS record must point at. Read it from the API or the console rather than remembered instructions.
  2. Publish the CNAME at your DNS provider, pointing the host at the cname_target. Flattened or chained CNAMEs are fine as long as the chain ends at that target.
  3. Verify. Hit Verify on the domain row (or POST /api/v1/organization/domains/{domainId}/verify). Once resolution matches, the domain flips to verifying and certificate issuance starts; around 15 minutes later it reaches active and serves HTTPS with nothing to upload or renew.
Removing a domain (DELETE .../domains/{domainId}) reverts your team to orbit.devotel.io. The full lifecycle — statuses pending → verifying → active / failed, how managed certificates are issued, and how to read provisioning state from the API — is covered in Custom domains and managed SSL.

How effective branding resolves

Every render of an authenticated dashboard page resolves branding for the requesting host: the host maps to an organization, that organization’s stored values fill their fields, and anything unset falls through to the platform default theme. For a subaccount with parent inheritance on, the parent’s values fill the gaps instead. The resolver is the same one GET /api/v1/branding/effective exposes — see the Branding API reference for the merged inherits_from_parent / inherited_from_organization_id diagnostics and the Cache-Control: private, max-age=60 client-caching contract. Unauthenticated surfaces are narrower. A white-labelled sign-in page on your custom domain can resolve the branding of the tenant that owns that host before any session exists (an IP-rate-limited lookup by host), and the public help center reads only the help_* field subset — it never receives your dashboard logo, support email, or custom domain. The help center portal guide documents that subset; the consent form reads only the terms and privacy URLs. If resolution ever fails, the render falls back to the neutral default theme rather than an error.

Where branding shows up

Only what ships: logo, favicon, colors, dashboard/brand name, support email, and the legal URLs. Concretely:
  • Dashboard chrome — sidebar header, active-item color, buttons, focus rings, browser tab title and icon.
  • Sign-in and public surfaces — the login screen, and the public consent form which links your terms_url / privacy_url.
  • White-label transactional emails — brand name, logo, and the support_email address where a template exposes them.
  • Help center — exclusively the separate help_* subset, never the dashboard fields.
Branding is cosmetic; it makes no claims about deliverability, sender reputation, or regulatory posture.

Reset and caching

Saving applies to the dashboard shell immediately — colors go live across the chrome without a reload, because the page applies the freshly saved tokens and refreshes the server-rendered layout. Reads elsewhere cache resolved branding for up to 60 seconds (the max-age=60 contract above), so a change can take up to a minute to appear on surfaces that poll the resolver — a new sign-in page load, an embedded widget. Reset to defaults (or POST /api/v1/organization/branding/reset) clears logo, favicon, colors, dashboard name, support email, and legal URLs behind a confirmation dialog. The dashboard falls back to platform defaults — or to your parent organization’s branding if inherit_branding_from_parent is on. Nothing is recoverable after a reset; re-upload assets to restore them.

Troubleshooting

  • Logo saved but the old one still shows — the uploaded image sits behind a cached URL; hard-refresh the page, and expect up to the 60-second resolver cache elsewhere. If the logo never appears after upload, the file was rejected: only PNG, JPEG, and WebP up to 2 MB are accepted (SVG and ICO fail at upload by design).
  • Color rejected on save — the server stores 6-digit hex only (#4F46E5). The form accepts what you paste while typing, but the API rejects 3-digit hex, rgb(), and hsl() values on save; normalize to 6-digit hex and re-save.
  • A color saved but nothing changed — confirm with GET /api/v1/branding/effective that the value persisted, and remember the ~60-second cache. Also check your role: writes need owner/admin.
  • Domain stuck in pending — the CNAME hasn’t resolved yet. Check the record points at the exact cname_target returned for that domain, wait out the TTL, then hit Verify again. An inconclusive DNS answer (resolver timeout, no answer) leaves the status at pending with no error recorded. Email-sending domains are a separate pipeline — for those, see email DNS drift and recovery.
  • Domain stuck in verifying — DNS matched and the certificate is provisioning (roughly 15 minutes). If it sits there longer, the row’s message tells you whether HTTPS activation is pending platform review; no action on your side. Never remove the CNAME mid-provisioning — that’s the common cause of a stall.
  • Domain in failed — the issuer reported a terminal failure; the error field on the domain row names the cause. Fix it (usually the DNS record) and verify again — the platform keeps retrying until you delete the domain.
  • 401/403 calling the branding endpoints — your role or API key lacks admin. The unauthenticated host-lookup path (X-Tenant-Host) is rate-limited by IP at a lower ceiling; don’t poll it in a loop.