# Update community theme colors

Change your community's theme, logos, loading animation or call-to-action button, sending only the parts you want to change.

- Endpoint: `PUT https://api.returning.ai/v1/appearance`
- Section: Community / Appearance
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `appearance` (Shown in the dashboard as "Appearance")
- Retries: Safe to repeat; the same values give the same result
- Guide: hand-written
- Verified: code, 2026-09-27
- Last updated: 26 Sep 2026
- Web page: https://docs.returning.ai/api-reference/community-appearance/update-community-theme-colors

## When to use this

- You switch the community to one of the built-in themes, or to a custom theme your team made in the dashboard.
- You update the community icon and logos after a rebrand.
- You turn the call-to-action button on or off, or change its text and link, for a campaign.

**Instead:** Use [Update community bot profile](https://docs.returning.ai/api-reference/community-appearance/update-community-bot-profile.md) instead to change the bot's name and avatar.

**Live change:** A successful call changes the community for every member straight away, including members who are online.

## Authentication

- Header: `Authorization: Bearer <API_KEY>`
- Permission: `appearance`

Use a Community API key with `appearance`, and keep it on your server. The key decides the community, so never send a community ID. The published path lacks `/v1`: call `PUT /v1/appearance`, because `PUT /appearance` returns `404`.

## Behaviour

Only the fields you send change; everything else keeps its value, down to single colours and single call-to-action settings. The change shows for every member straight away. Members aren't notified.

A theme is picked by `name`. For a built-in theme, the colours come from that theme and any `palette` you send is ignored. For a custom theme made in your dashboard, its saved colours are used and the colours you send in `palette` replace those. A name that is neither returns `400`. The built-in dark themes are `black-beauty`, `dark-knight`, `botanical-forest`, `rustic-pottery` and `hearts-desire`. The built-in light themes are `aqua-lolly`, `lush-blush`, `white-smoke`, `prairie-dance`, `farsighted` and `violet-dream`.

Images must be `https` or `http` URLs, or paths starting with `/assets/files/`, and must end in `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp` or `.svg`. Send `null` to remove an image.

## Request

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key with `appearance`. (`Bearer <API_KEY>`) |
| `Content-Type` | `string` | Yes | Request body format. (`application/json`) |

### Body

Send a JSON object with one or more of `theme`, `branding`, `loadingAnimation` and `callToAction`. Any field not listed here is rejected with `400`.

Colours are hex (`#6755ff`, also 3, 4 or 8 digits), `rgb()` or `rgba()` values, or one of `var(--accent-1)`, `var(--text-1)` and `var(--divider-lines-1)`. Named colours such as `red` are rejected.

For a loading animation, send `mode: "preset"` with `preset`, or `mode: "custom"` with `activeTheme` and a `custom` entry for that theme. Each custom entry sets `type` and fills only the matching `html` or `lottie` field.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `theme` | `object` | No | Theme settings. Send only the parts you change. |
| `theme.font` | `string` | No | The font for the whole community. (`Lato`, `Roboto`, `Noto`, `Open Sans`, `Source Sans Pro`, `Inter`, `Montserrat`, `Poppins`, `Nunito`, `Prata`, `Bebas Neue`, `Monospace`, `Courier`, `Monaco`, `Quicksand`, `Fira Code`, `Fira Sans`, `Rubik`, `Noto Sans`, `Lora`, `Playfair Display`) |
| `theme.defaultMode` | `string` | No | Whether members see the dark or the light theme by default. (`light`, `dark`) |
| `theme.dark` | `object` | No | The dark theme. |
| `theme.dark.name` | `string` | No | A built-in theme name, such as `dark-knight`, or the name of a custom theme made in your dashboard. Required when you send `palette`. (Theme name) |
| `theme.dark.palette` | `object` | No | Colours to change. Used only with a custom theme; a built-in theme always uses its own colours. |
| `theme.dark.palette.accent1` | `string` | No | Main accent colour. (Hex or rgb() colour) |
| `theme.dark.palette.accent2` | `string` | No | Second accent shade. (Hex or rgb() colour) |
| `theme.dark.palette.accent3` | `string` | No | Third accent shade. (Hex or rgb() colour) |
| `theme.dark.palette.accent4` | `string` | No | Fourth accent shade. (Hex or rgb() colour) |
| `theme.dark.palette.accentGradient` | `string` | No | Accent gradient, any CSS gradient value such as `linear-gradient(90deg, #596cff 0%, #8f5cff 100%)`. (Any non-empty CSS value) |
| `theme.dark.palette.text1` | `string` | No | Main text colour. (Hex or rgb() colour) |
| `theme.dark.palette.text2` | `string` | No | Second text shade. (Hex or rgb() colour) |
| `theme.dark.palette.text3` | `string` | No | Third text shade. (Hex or rgb() colour) |
| `theme.dark.palette.text4` | `string` | No | Fourth text shade. (Hex or rgb() colour) |
| `theme.dark.palette.text5` | `string` | No | Fifth text shade. (Hex or rgb() colour) |
| `theme.dark.palette.text6` | `string` | No | Sixth text shade. (Hex or rgb() colour) |
| `theme.dark.palette.text7` | `string` | No | Inverted text colour, the opposite of `text1`. Worked out from `text1` when you leave it out. (Hex or rgb() colour) |
| `theme.dark.palette.background1` | `string` | No | Main background colour. (Hex or rgb() colour) |
| `theme.dark.palette.background2` | `string` | No | Second background shade. (Hex or rgb() colour) |
| `theme.dark.palette.background3` | `string` | No | Third background shade. (Hex or rgb() colour) |
| `theme.dark.palette.background4` | `string` | No | Fourth background shade. (Hex or rgb() colour) |
| `theme.dark.palette.background5` | `string` | No | Fifth background shade. (Hex or rgb() colour) |
| `theme.dark.palette.background6` | `string` | No | Sixth background shade. (Hex or rgb() colour) |
| `theme.dark.palette.background7` | `string` | No | Seventh background shade. (Hex or rgb() colour) |
| `theme.dark.palette.divider1` | `string` | No | Main divider line colour. (Hex or rgb() colour) |
| `theme.dark.palette.divider2` | `string` | No | Second divider line colour. (Hex or rgb() colour) |
| `theme.dark.palette.shadow` | `string` | No | Shadow, any CSS shadow value such as `0 8px 24px rgba(0, 0, 0, 0.24)`. (Any non-empty CSS value) |
| `theme.dark.palette.label` | `string` | No | Background colour of labels and mentions. (Hex or rgb() colour) |
| `theme.dark.palette.mentionBackground` | `string` | No | Older name for `label`. Send `label` instead. (Hex or rgb() colour; must equal `label` when both are sent) |
| `theme.dark.palette.scrollThumb` | `string` | No | Scroll bar thumb colour. (Hex or rgb() colour) |
| `theme.dark.palette.scrollTrack` | `string` | No | Scroll bar track colour. (Hex or rgb() colour) |
| `theme.light` | `object` | No | The light theme. |
| `theme.light.name` | `string` | No | A built-in theme name, such as `white-smoke`, or the name of a custom theme made in your dashboard. Required when you send `palette`. (Theme name) |
| `theme.light.palette` | `object` | No | Colours to change. Used only with a custom theme; a built-in theme always uses its own colours. |
| `theme.light.palette.accent1` | `string` | No | Main accent colour. (Hex or rgb() colour) |
| `theme.light.palette.accent2` | `string` | No | Second accent shade. (Hex or rgb() colour) |
| `theme.light.palette.accent3` | `string` | No | Third accent shade. (Hex or rgb() colour) |
| `theme.light.palette.accent4` | `string` | No | Fourth accent shade. (Hex or rgb() colour) |
| `theme.light.palette.accentGradient` | `string` | No | Accent gradient, any CSS gradient value such as `linear-gradient(90deg, #596cff 0%, #8f5cff 100%)`. (Any non-empty CSS value) |
| `theme.light.palette.text1` | `string` | No | Main text colour. (Hex or rgb() colour) |
| `theme.light.palette.text2` | `string` | No | Second text shade. (Hex or rgb() colour) |
| `theme.light.palette.text3` | `string` | No | Third text shade. (Hex or rgb() colour) |
| `theme.light.palette.text4` | `string` | No | Fourth text shade. (Hex or rgb() colour) |
| `theme.light.palette.text5` | `string` | No | Fifth text shade. (Hex or rgb() colour) |
| `theme.light.palette.text6` | `string` | No | Sixth text shade. (Hex or rgb() colour) |
| `theme.light.palette.text7` | `string` | No | Inverted text colour, the opposite of `text1`. Worked out from `text1` when you leave it out. (Hex or rgb() colour) |
| `theme.light.palette.background1` | `string` | No | Main background colour. (Hex or rgb() colour) |
| `theme.light.palette.background2` | `string` | No | Second background shade. (Hex or rgb() colour) |
| `theme.light.palette.background3` | `string` | No | Third background shade. (Hex or rgb() colour) |
| `theme.light.palette.background4` | `string` | No | Fourth background shade. (Hex or rgb() colour) |
| `theme.light.palette.background5` | `string` | No | Fifth background shade. (Hex or rgb() colour) |
| `theme.light.palette.background6` | `string` | No | Sixth background shade. (Hex or rgb() colour) |
| `theme.light.palette.background7` | `string` | No | Seventh background shade. (Hex or rgb() colour) |
| `theme.light.palette.divider1` | `string` | No | Main divider line colour. (Hex or rgb() colour) |
| `theme.light.palette.divider2` | `string` | No | Second divider line colour. (Hex or rgb() colour) |
| `theme.light.palette.shadow` | `string` | No | Shadow, any CSS shadow value such as `0 8px 24px rgba(0, 0, 0, 0.24)`. (Any non-empty CSS value) |
| `theme.light.palette.label` | `string` | No | Background colour of labels and mentions. (Hex or rgb() colour) |
| `theme.light.palette.mentionBackground` | `string` | No | Older name for `label`. Send `label` instead. (Hex or rgb() colour; must equal `label` when both are sent) |
| `theme.light.palette.scrollThumb` | `string` | No | Scroll bar thumb colour. (Hex or rgb() colour) |
| `theme.light.palette.scrollTrack` | `string` | No | Scroll bar track colour. (Hex or rgb() colour) |
| `branding` | `object` | No | The community's images. |
| `branding.icon` | `string` | No | The community icon, or `null` to remove it. (Image URL or path; nullable) |
| `branding.logo` | `object` | No | The logos for each theme. |
| `branding.logo.dark` | `string` | No | The logo shown with the dark theme, or `null` to remove it. (Image URL or path; nullable) |
| `branding.logo.light` | `string` | No | The logo shown with the light theme, or `null` to remove it. (Image URL or path; nullable) |
| `loadingAnimation` | `object` | No | The animation members see while the community loads. |
| `loadingAnimation.mode` | `string` | No | `preset` for a built-in animation, or `custom` for your own. (`preset`, `custom`) |
| `loadingAnimation.preset` | `string` | No | The built-in animation. Required when `mode` is `preset`. (`bar`, `default`, `circle`, `square`) |
| `loadingAnimation.activeTheme` | `string` | No | Which custom animation to show. Required when `mode` is `custom`. (`dark`, `light`) |
| `loadingAnimation.custom` | `object` | No | Your own animations, one for each theme. |
| `loadingAnimation.custom.dark` | `object` | No | The custom animation for the dark theme. |
| `loadingAnimation.custom.dark.type` | `string` | No | `html` or `lottie`. Send the matching field and leave the other empty. (`html`, `lottie`) |
| `loadingAnimation.custom.dark.html` | `string` | No | HTML for the animation. Scripts, event handlers, `iframe` and `embed` tags, and `javascript:` or `data:` URLs are rejected. |
| `loadingAnimation.custom.dark.lottie` | `string` | No | Lottie animation JSON as a string, or a URL or path ending in `.json`. |
| `loadingAnimation.custom.light` | `object` | No | The custom animation for the light theme. |
| `loadingAnimation.custom.light.type` | `string` | No | `html` or `lottie`. Send the matching field and leave the other empty. (`html`, `lottie`) |
| `loadingAnimation.custom.light.html` | `string` | No | HTML for the animation. Scripts, event handlers, `iframe` and `embed` tags, and `javascript:` or `data:` URLs are rejected. |
| `loadingAnimation.custom.light.lottie` | `string` | No | Lottie animation JSON as a string, or a URL or path ending in `.json`. |
| `callToAction` | `object` | No | The call-to-action button. |
| `callToAction.isEnabled` | `boolean` | No | Show the button. |
| `callToAction.isMobileEnabled` | `boolean` | No | Show the button on mobile. |
| `callToAction.content` | `object` | No | What the button says and where it goes. |
| `callToAction.content.text` | `string` | No | The button text. Can't be empty when you also send `isEnabled` as `true`. |
| `callToAction.content.link` | `string` | No | Where the button goes, an `https` or `http` URL. An empty string removes the link. (URL or empty, max 2048 chars) |
| `callToAction.content.linkBehavior` | `string` | No | Open the link in a `new` tab or the `same` one. (`new`, `same`) |
| `callToAction.content.iconImage` | `string` | No | An icon shown on the button, or `null` to remove it. (Image URL or path; nullable) |
| `callToAction.style` | `object` | No | How the button looks. |
| `callToAction.style.shape` | `string` | No | The button shape. (`square`, `rounded`, `circle`) |
| `callToAction.style.backgroundColor` | `string` | No | The button colour. (Hex or rgb() colour) |
| `callToAction.style.borderSize` | `string` | No | The border width in whole pixels. (`0px` to `20px`) |
| `callToAction.style.borderColor` | `string` | No | The border colour. (Hex or rgb() colour) |
| `callToAction.typography` | `object` | No | The button text style. |
| `callToAction.typography.fontFamily` | `string` | No | The button font. (`Lato`, `Roboto`, `Noto`, `Open Sans`, `Source Sans Pro`, `Inter`, `Montserrat`, `Poppins`, `Nunito`, `Prata`, `Bebas Neue`, `Monospace`, `Courier`, `Monaco`, `Quicksand`, `Fira Code`, `Fira Sans`, `Rubik`, `Noto Sans`, `Lora`, `Playfair Display`) |
| `callToAction.typography.fontSize` | `string` | No | The text size in whole pixels. (`1px` to `20px`) |
| `callToAction.typography.fontColor` | `string` | No | The text colour. (Hex or rgb() colour) |
| `callToAction.typography.fontStyle` | `string` | No | The text style. (`normal`, `italic`, `bold`) |
| `callToAction.typography.textAlign` | `string` | No | The text alignment. (`left`, `center`, `right`) |

### Example request

```bash
curl --request PUT \
  --url https://api.returning.ai/v1/appearance \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "theme": {
      "defaultMode": "dark",
      "dark": {
        "name": "dark-knight"
      }
    },
    "branding": {
      "logo": {
        "dark": "https://cdn.example.com/brand/logo-dark.svg",
        "light": "https://cdn.example.com/brand/logo-light.svg"
      }
    },
    "callToAction": {
      "isEnabled": true,
      "content": {
        "text": "Open an account",
        "link": "https://www.example.com/open-account",
        "linkBehavior": "new"
      }
    }
  }'
```

## Response

A `200` returns the community's whole appearance after the change in `data`, including the parts you didn't send. Palette colours come back under `label`, never `mentionBackground`.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `meta` | `object` | always | - |
| `meta.status` | `string` | always | Result of the request. (`success`) |
| `meta.statusCode` | `integer` | always | The HTTP status, repeated. (`200`) |
| `message` | `string` | always | Human-readable summary. Do not branch on it. |
| `data` | `object` | always | The community's whole appearance after the change, not only the parts you sent. |
| `data._id` | `string` | always | Your community's ID, the same as `communityID`. |
| `data.communityID` | `string` | always | Your community's ID. |
| `data.theme` | `object` | - | The theme settings. |
| `data.theme.font` | `string` | always | The community font. |
| `data.theme.defaultMode` | `string` | always | The default theme, `dark` or `light`. |
| `data.theme.dark` | `object` | always | The dark theme. |
| `data.theme.dark.name` | `string` | always | The dark theme's name. |
| `data.theme.dark.palette` | `object` | always | The dark theme's colours. A key is present only when it has a value. |
| `data.theme.dark.palette.accent1` | `string` | when set | Main accent colour. |
| `data.theme.dark.palette.accent2` | `string` | when set | Second accent shade. |
| `data.theme.dark.palette.accent3` | `string` | when set | Third accent shade. |
| `data.theme.dark.palette.accent4` | `string` | when set | Fourth accent shade. |
| `data.theme.dark.palette.text1` | `string` | when set | Main text colour. |
| `data.theme.dark.palette.text2` | `string` | when set | Second text shade. |
| `data.theme.dark.palette.text3` | `string` | when set | Third text shade. |
| `data.theme.dark.palette.text4` | `string` | when set | Fourth text shade. |
| `data.theme.dark.palette.text5` | `string` | when set | Fifth text shade. |
| `data.theme.dark.palette.text6` | `string` | when set | Sixth text shade. |
| `data.theme.dark.palette.background1` | `string` | when set | Main background colour. |
| `data.theme.dark.palette.background2` | `string` | when set | Second background shade. |
| `data.theme.dark.palette.background3` | `string` | when set | Third background shade. |
| `data.theme.dark.palette.background4` | `string` | when set | Fourth background shade. |
| `data.theme.dark.palette.background5` | `string` | when set | Fifth background shade. |
| `data.theme.dark.palette.background6` | `string` | when set | Sixth background shade. |
| `data.theme.dark.palette.background7` | `string` | when set | Seventh background shade. |
| `data.theme.dark.palette.divider1` | `string` | when set | Main divider line colour. |
| `data.theme.dark.palette.divider2` | `string` | when set | Second divider line colour. |
| `data.theme.dark.palette.shadow` | `string` | when set | Shadow, any CSS shadow value such as `0 8px 24px rgba(0, 0, 0, 0.24)`. |
| `data.theme.dark.palette.scrollThumb` | `string` | when set | Scroll bar thumb colour. |
| `data.theme.dark.palette.scrollTrack` | `string` | when set | Scroll bar track colour. |
| `data.theme.dark.palette.accentGradient` | `string` | when set | Accent gradient, any CSS gradient value such as `linear-gradient(90deg, #596cff 0%, #8f5cff 100%)`. |
| `data.theme.dark.palette.text7` | `string` | when set | Inverted text colour, the opposite of `text1`. Worked out from `text1` when you leave it out. |
| `data.theme.dark.palette.label` | `string` | when set | Background colour of labels and mentions. |
| `data.theme.dark.colorSettings` | `object` | when set | One entry per colour, used by the dashboard's colour editor. You can ignore it. |
| `data.theme.light` | `object` | always | The light theme. |
| `data.theme.light.name` | `string` | always | The light theme's name. |
| `data.theme.light.palette` | `object` | always | The light theme's colours. A key is present only when it has a value. |
| `data.theme.light.palette.accent1` | `string` | when set | Main accent colour. |
| `data.theme.light.palette.accent2` | `string` | when set | Second accent shade. |
| `data.theme.light.palette.accent3` | `string` | when set | Third accent shade. |
| `data.theme.light.palette.accent4` | `string` | when set | Fourth accent shade. |
| `data.theme.light.palette.text1` | `string` | when set | Main text colour. |
| `data.theme.light.palette.text2` | `string` | when set | Second text shade. |
| `data.theme.light.palette.text3` | `string` | when set | Third text shade. |
| `data.theme.light.palette.text4` | `string` | when set | Fourth text shade. |
| `data.theme.light.palette.text5` | `string` | when set | Fifth text shade. |
| `data.theme.light.palette.text6` | `string` | when set | Sixth text shade. |
| `data.theme.light.palette.background1` | `string` | when set | Main background colour. |
| `data.theme.light.palette.background2` | `string` | when set | Second background shade. |
| `data.theme.light.palette.background3` | `string` | when set | Third background shade. |
| `data.theme.light.palette.background4` | `string` | when set | Fourth background shade. |
| `data.theme.light.palette.background5` | `string` | when set | Fifth background shade. |
| `data.theme.light.palette.background6` | `string` | when set | Sixth background shade. |
| `data.theme.light.palette.background7` | `string` | when set | Seventh background shade. |
| `data.theme.light.palette.divider1` | `string` | when set | Main divider line colour. |
| `data.theme.light.palette.divider2` | `string` | when set | Second divider line colour. |
| `data.theme.light.palette.shadow` | `string` | when set | Shadow, any CSS shadow value such as `0 8px 24px rgba(0, 0, 0, 0.24)`. |
| `data.theme.light.palette.scrollThumb` | `string` | when set | Scroll bar thumb colour. |
| `data.theme.light.palette.scrollTrack` | `string` | when set | Scroll bar track colour. |
| `data.theme.light.palette.accentGradient` | `string` | when set | Accent gradient, any CSS gradient value such as `linear-gradient(90deg, #596cff 0%, #8f5cff 100%)`. |
| `data.theme.light.palette.text7` | `string` | when set | Inverted text colour, the opposite of `text1`. Worked out from `text1` when you leave it out. |
| `data.theme.light.palette.label` | `string` | when set | Background colour of labels and mentions. |
| `data.theme.light.colorSettings` | `object` | when set | One entry per colour, used by the dashboard's colour editor. You can ignore it. |
| `data.branding` | `object` | - | The community's images. |
| `data.branding.icon` | `string` | - | The community icon, or `null`. (Nullable) |
| `data.branding.logo` | `object` | - | The logos. |
| `data.branding.logo.dark` | `string` | - | The dark-theme logo, or `null`. (Nullable) |
| `data.branding.logo.light` | `string` | - | The light-theme logo, or `null`. (Nullable) |
| `data.loadingAnimation` | `object` | - | The loading animation settings. |
| `data.loadingAnimation.mode` | `string` | - | `preset` or `custom`. |
| `data.loadingAnimation.preset` | `string` | - | The built-in animation. |
| `data.loadingAnimation.activeTheme` | `string` | - | Which custom animation is shown. |
| `data.loadingAnimation.custom` | `object` | when set | The custom animations. |
| `data.loadingAnimation.custom.dark` | `object` | when set | The dark-theme animation. |
| `data.loadingAnimation.custom.dark.type` | `string` | always | `html` or `lottie`. |
| `data.loadingAnimation.custom.dark.html` | `string` | always | The HTML animation. |
| `data.loadingAnimation.custom.dark.lottie` | `string` | always | The Lottie animation. |
| `data.loadingAnimation.custom.light` | `object` | when set | The light-theme animation. |
| `data.loadingAnimation.custom.light.type` | `string` | always | `html` or `lottie`. |
| `data.loadingAnimation.custom.light.html` | `string` | always | The HTML animation. |
| `data.loadingAnimation.custom.light.lottie` | `string` | always | The Lottie animation. |
| `data.callToAction` | `object` | - | The call-to-action button. |
| `data.callToAction.isEnabled` | `boolean` | - | `true` when the button is shown. |
| `data.callToAction.isMobileEnabled` | `boolean` | - | `true` when the button is shown on mobile. |
| `data.callToAction.content` | `object` | - | The button text and link. |
| `data.callToAction.content.text` | `string` | when set | The button text. |
| `data.callToAction.content.link` | `string` | when set | The button link. |
| `data.callToAction.content.linkBehavior` | `string` | when set | `new` or `same`. |
| `data.callToAction.content.iconImage` | `string` | - | The button icon, or `null`. (Nullable) |
| `data.callToAction.style` | `object` | - | The button style. |
| `data.callToAction.style.shape` | `string` | when set | The button shape. |
| `data.callToAction.style.backgroundColor` | `string` | when set | The button colour. |
| `data.callToAction.style.borderSize` | `string` | when set | The border width. |
| `data.callToAction.style.borderColor` | `string` | when set | The border colour. |
| `data.callToAction.typography` | `object` | - | The button text style. |
| `data.callToAction.typography.fontFamily` | `string` | when set | The button font. |
| `data.callToAction.typography.fontSize` | `string` | when set | The text size. |
| `data.callToAction.typography.fontColor` | `string` | when set | The text colour. |
| `data.callToAction.typography.fontStyle` | `string` | when set | The text style. |
| `data.callToAction.typography.textAlign` | `string` | when set | The text alignment. |
| `data.createdAt` | `string` | always | When the community was created. |
| `data.updatedAt` | `string` | always | When the community last changed. |

### Example response (200)

```json
{
  "meta": {
    "status": "success",
    "statusCode": 200
  },
  "message": "Update community appearance success.",
  "data": {
    "_id": "66f000000000000000000010",
    "communityID": "66f000000000000000000010",
    "theme": {
      "font": "Inter",
      "defaultMode": "dark",
      "dark": {
        "name": "dark-knight",
        "palette": {
          "accent1": "rgb(224, 208, 162)",
          "accent2": "rgb(239, 225, 186)",
          "accent3": "rgb(250, 240, 212)",
          "accent4": "rgb(254, 249, 236)",
          "text1": "rgb(252, 252, 252)",
          "text2": "rgb(210, 217, 224)",
          "text3": "rgb(200, 210, 220)",
          "text4": "rgb(158, 171, 185)",
          "text5": "rgb(151, 165, 181)",
          "text6": "rgb(133, 147, 164)",
          "text7": "rgb(27, 28, 29)",
          "background1": "rgb(6, 9, 33)",
          "background2": "rgb(13, 17, 42)",
          "background3": "rgb(23, 26, 54)",
          "background4": "rgb(23, 27, 56)",
          "background5": "rgb(31, 35, 65)",
          "background6": "rgb(37, 41, 73)",
          "background7": "rgb(53, 59, 92)",
          "divider1": "rgb(79, 92, 108)",
          "divider2": "rgb(158, 171, 185)",
          "shadow": "rgba(6, 9, 33, 0.5)",
          "label": "rgb(23, 26, 54)",
          "scrollThumb": "rgb(34, 34, 34)",
          "scrollTrack": "rgb(59, 59, 59)"
        },
        "colorSettings": {
          "accent1": {
            "type": "solid",
            "solid": "rgb(224, 208, 162)"
          },
          "accent2": {
            "type": "solid",
            "solid": "rgb(239, 225, 186)"
          },
          "accent3": {
            "type": "solid",
            "solid": "rgb(250, 240, 212)"
          },
          "accent4": {
            "type": "solid",
            "solid": "rgb(254, 249, 236)"
          },
          "text1": {
            "type": "solid",
            "solid": "rgb(252, 252, 252)"
          },
          "text2": {
            "type": "solid",
            "solid": "rgb(210, 217, 224)"
          },
          "text3": {
            "type": "solid",
            "solid": "rgb(200, 210, 220)"
          },
          "text4": {
            "type": "solid",
            "solid": "rgb(158, 171, 185)"
          },
          "text5": {
            "type": "solid",
            "solid": "rgb(151, 165, 181)"
          },
          "text6": {
            "type": "solid",
            "solid": "rgb(133, 147, 164)"
          },
          "text7": {
            "type": "solid",
            "solid": "rgb(27, 28, 29)"
          },
          "background1": {
            "type": "solid",
            "solid": "rgb(6, 9, 33)"
          },
          "background2": {
            "type": "solid",
            "solid": "rgb(13, 17, 42)"
          },
          "background3": {
            "type": "solid",
            "solid": "rgb(23, 26, 54)"
          },
          "background4": {
            "type": "solid",
            "solid": "rgb(23, 27, 56)"
          },
          "background5": {
            "type": "solid",
            "solid": "rgb(31, 35, 65)"
          },
          "background6": {
            "type": "solid",
            "solid": "rgb(37, 41, 73)"
          },
          "background7": {
            "type": "solid",
            "solid": "rgb(53, 59, 92)"
          },
          "divider1": {
            "type": "solid",
            "solid": "rgb(79, 92, 108)"
          },
          "divider2": {
            "type": "solid",
            "solid": "rgb(158, 171, 185)"
          },
          "shadow": {
            "type": "solid",
            "solid": "rgba(6, 9, 33, 0.5)"
          },
          "label": {
            "type": "solid",
            "solid": "rgb(23, 26, 54)"
          },
          "scrollThumb": {
            "type": "solid",
            "solid": "rgb(34, 34, 34)"
          },
          "scrollTrack": {
            "type": "solid",
            "solid": "rgb(59, 59, 59)"
          }
        }
      },
      "light": {
        "name": "white-smoke",
        "palette": {
          "accent1": "rgb(48, 65, 97)",
          "accent2": "rgb(64, 87, 130)",
          "accent3": "rgb(159, 171, 192)",
          "accent4": "rgb(193, 202, 218)",
          "text1": "rgb(27, 28, 29)",
          "text2": "rgb(71, 71, 71)",
          "text3": "rgb(84, 84, 84)",
          "text4": "rgb(103, 103, 103)",
          "text5": "rgb(119, 119, 119)",
          "text6": "rgb(146, 146, 146)",
          "text7": "rgb(252, 252, 252)",
          "background1": "rgb(252, 252, 252)",
          "background2": "rgb(240, 240, 240)",
          "background3": "rgb(233, 233, 233)",
          "background4": "rgb(228, 228, 228)",
          "background5": "rgb(211, 211, 211)",
          "background6": "rgb(199, 199, 199)",
          "background7": "rgb(167, 167, 167)",
          "divider1": "rgb(146, 146, 146)",
          "divider2": "rgb(103, 103, 103)",
          "shadow": "rgba(27, 28, 29, 0.35)",
          "label": "rgb(233, 233, 233)",
          "scrollThumb": "rgb(203, 203, 203)",
          "scrollTrack": "rgb(234, 234, 234)"
        },
        "colorSettings": {
          "accent1": {
            "type": "solid",
            "solid": "rgb(48, 65, 97)"
          },
          "accent2": {
            "type": "solid",
            "solid": "rgb(64, 87, 130)"
          },
          "accent3": {
            "type": "solid",
            "solid": "rgb(159, 171, 192)"
          },
          "accent4": {
            "type": "solid",
            "solid": "rgb(193, 202, 218)"
          },
          "text1": {
            "type": "solid",
            "solid": "rgb(27, 28, 29)"
          },
          "text2": {
            "type": "solid",
            "solid": "rgb(71, 71, 71)"
          },
          "text3": {
            "type": "solid",
            "solid": "rgb(84, 84, 84)"
          },
          "text4": {
            "type": "solid",
            "solid": "rgb(103, 103, 103)"
          },
          "text5": {
            "type": "solid",
            "solid": "rgb(119, 119, 119)"
          },
          "text6": {
            "type": "solid",
            "solid": "rgb(146, 146, 146)"
          },
          "text7": {
            "type": "solid",
            "solid": "rgb(252, 252, 252)"
          },
          "background1": {
            "type": "solid",
            "solid": "rgb(252, 252, 252)"
          },
          "background2": {
            "type": "solid",
            "solid": "rgb(240, 240, 240)"
          },
          "background3": {
            "type": "solid",
            "solid": "rgb(233, 233, 233)"
          },
          "background4": {
            "type": "solid",
            "solid": "rgb(228, 228, 228)"
          },
          "background5": {
            "type": "solid",
            "solid": "rgb(211, 211, 211)"
          },
          "background6": {
            "type": "solid",
            "solid": "rgb(199, 199, 199)"
          },
          "background7": {
            "type": "solid",
            "solid": "rgb(167, 167, 167)"
          },
          "divider1": {
            "type": "solid",
            "solid": "rgb(146, 146, 146)"
          },
          "divider2": {
            "type": "solid",
            "solid": "rgb(103, 103, 103)"
          },
          "shadow": {
            "type": "solid",
            "solid": "rgba(27, 28, 29, 0.35)"
          },
          "label": {
            "type": "solid",
            "solid": "rgb(233, 233, 233)"
          },
          "scrollThumb": {
            "type": "solid",
            "solid": "rgb(203, 203, 203)"
          },
          "scrollTrack": {
            "type": "solid",
            "solid": "rgb(234, 234, 234)"
          }
        }
      }
    },
    "branding": {
      "icon": "https://cdn.example.com/brand/icon.png",
      "logo": {
        "dark": "https://cdn.example.com/brand/logo-dark.svg",
        "light": "https://cdn.example.com/brand/logo-light.svg"
      }
    },
    "loadingAnimation": {
      "mode": "preset",
      "preset": "default"
    },
    "callToAction": {
      "isEnabled": true,
      "isMobileEnabled": true,
      "content": {
        "text": "Open an account",
        "link": "https://www.example.com/open-account",
        "linkBehavior": "new",
        "iconImage": null
      },
      "style": {
        "shape": "rounded",
        "backgroundColor": "var(--accent-1)",
        "borderSize": "0px",
        "borderColor": "var(--accent-1)"
      },
      "typography": {
        "fontFamily": "Inter",
        "fontSize": "14px",
        "fontColor": "var(--text-1)",
        "fontStyle": "bold",
        "textAlign": "center"
      }
    },
    "createdAt": "2026-09-20T08:30:00.000Z",
    "updatedAt": "2026-09-26T08:30:00.000Z"
  }
}
```

## Errors

Every error carries `meta.status` and `meta.statusCode`, with the reason in `detail`. Key errors and field validation errors also carry `meta.code`; other `400` errors and the `500` and `502` errors don't.

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | - | `detail` says which: `Request body must be a non-empty object` (send at least one of `theme`, `branding`, `loadingAnimation` or `callToAction`), `Theme 'name' not found for mode 'dark'` (use a built-in theme name or a custom theme from your dashboard), or the unsafe loading-animation HTML message (remove scripts, event handlers and embedded frames). These `400` errors have no `meta.code`. Nothing changed. |
| 400 | `VALIDATION_FAILED` | A field breaks its rule, such as a colour that isn't hex or `rgb()`, a `palette` without `name`, a loading animation whose `mode` doesn't match its other fields, or a field this endpoint doesn't accept. `detail` names each field. Nothing changed. |
| 401 | `AUTH_API_KEY_REQUIRED` | No key was sent. Send `Authorization: Bearer <API_KEY>`. |
| 401 | `AUTH_API_KEY_INVALID` | The key is unknown, expired or malformed. Use a current Community API key. |
| 403 | `AUTH_PERMISSION_REQUIRED` | The key lacks `appearance`. Add the permission in Settings > Integration > API Keys. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | - | The community that owns this key no longer exists. Contact Returning.AI support. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 500 | - | The change failed unexpectedly. Retry with backoff; sending the same values again is safe. |
| 502 | - | The change couldn't be completed just now (`Upstream service is temporarily unavailable.`). Retry with backoff. |
| 401 | `AUTH_API_KEY_VALIDATION_FAILED` | The key could not be checked just now. Retry with backoff; the key itself may be fine. |

**Retries:** Sending the same values twice gives the same result, so a retry after a timeout, a `500` or a `502` is safe. Use bounded exponential backoff. Over the [rate limit](https://docs.returning.ai/how-it-works.md#rate-limits), requests return `429`; wait for the window to reset, then retry.

## Next step

- [Update community bot profile](https://docs.returning.ai/api-reference/community-appearance/update-community-bot-profile.md): `PUT /v1/community-bot`. Give the community bot a name and avatar that match the new look.
