Customize help center branding and themes with the Notiondesk API

Update Notiondesk help center branding through the REST API: colors, fonts, layout, header and footer links, search display, and themes.

7 min read

The Notiondesk API lets you read and change your help center's branding: colors, fonts, layout, header and footer, links, search and feedback display, and theme. Use it to roll out the same brand across several help centers, or to keep your branding in code next to the rest of your design system.

MethodPathScopeDoes
GET/sites/{site_id}/settings/customizereadReads the branding
PATCH/sites/{site_id}/settings/customizeadminUpdates the branding
GET/sites/{site_id}/themesreadLists the available themes

Branding is visible on every public page, so updating it needs the admin scope, not write. Only a key created by a workspace owner or Admin holds admin.

To change branding in the dashboard instead, see Customize your help center colors and fonts.

What the API does not change

These stay dashboard-only. The read route does not return them, and an update that names one answers 400 validation_error:

  • logos (light and dark), footer logos (light and dark), favicon, social media image and header images (light and dark).

Read your branding

curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/settings/customize" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16"

The response holds exactly the fields the update accepts, under the same names. A shortened example:

{
  "colors": {
    "primary": "#2563eb",
    "text": "#111827",
    "link": "#2563eb",
    "link_hover": "#1d4ed8",
    "header": "#2563eb",
    "header_text": "#ffffff",
    "background": "#ffffff",
    "footer_background": ""
  },
  "appearance": null,
  "layout_collection": "column_2",
  "layout_article": "column_1",
  "footer_layout": "compact",
  "primary_font": "Inter",
  "header_links": [{"title": "Docs", "url": "https://example.com/docs"}],
  "footer_links": [{"title": "Product", "links": [{"title": "Pricing", "url": "https://example.com/pricing"}]}],
  "show_powered_by_badge": false,
  "theme": null
}
  • A color that was never set reads "". colors.dark holds the dark mode colors, and is absent when the help center has no dark palette.
  • A list that holds nothing reads [].
  • theme is the code of the current theme, or null.

Update your branding

curl -i -X PATCH "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/settings/customize" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16" \
  -H "Content-Type: application/json" \
  -d '{"primary_font": "Inter", "colors": {"primary": "#2563eb"}, "header_links": [{"title": "Docs", "url": "https://example.com/docs"}]}'

The route answers 204 No Content. Read the branding again to confirm the change.

  • A field you leave out keeps its value. Inside colors, a color you leave out keeps its value too.
  • A list you send replaces the whole stored list, and [] empties it.
  • Colors are #rrggbb hexadecimal values, or "". Short forms such as #fff are rejected.
  • Send JSON booleans. The values 0 and "false" are read as true, and null as false.
Every accepted update refreshes the whole help center: Notiondesk clears its cached pages and rebuilds every page, whatever the update changed. Send every change in one request, not one request per field.

Safe updates: read, change, send back

The safest way to update branding is to send back what you read, with your changes applied. A field sent with its current value is accepted on any plan, so this pattern never trips a plan limit on fields you did not touch.

const url = "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/settings/customize";
const headers = {
  Authorization: `Bearer ${process.env.NOTIONDESK_API_KEY}`,
  "nd-version": "2026-10-16",
  "Content-Type": "application/json",
};

const branding = await (await fetch(url, { headers })).json();
branding.colors.primary = "#7c3aed";
branding.colors.link = "#7c3aed";

const response = await fetch(url, { method: "PATCH", headers, body: JSON.stringify(branding) });
console.log(response.status);

A body sent back can still be refused in two cases. Fix the value in the dashboard, or leave that field out of the body:

  • a stored color in a short form such as #fff;
  • a stored list longer than the limits below.

Fields you can change

AreaFields
Colorscolors with primary, text, link, link_hover, header, header_top, header_text, header_top_text, header_link, header_link_hover, background, footer_background, footer_text, article_card_background, collection_card_background, aside_menu_text, aside_menu_text_hover, aside_menu_background_hover, and dark with the same fields for dark mode
Appearanceappearance (default: light, dark or system; strict: boolean)
Fonts and layoutprimary_font, secondary_font, layout_collection, layout_article (column_1, column_2 or column_3), theme
Headerheader_variant (hero or bar), headline_size, header_background_type (color, image or gradient), header_gradient_type, header_gradient_angle, header_gradient_colors, header_shape_type, header_links, header_link_translations, homepage_link, homepage_link_translations
Searchsearch_bar_length, search_bar_alignment, search_bar_corner_style, search_bar_shadow, search_result_variant, instant_search, segmented_search_results, ai_search_enabled, ai_search_display_mode, ai_search_aside_position
Collectionscollections_style, collection_card_corner_style, collection_section_variant, collection_content_variant, collapsable_sub_categories, collapsable_sub_categories_default_state, show_collection_icons, show_collection_descriptions, show_collection_content, show_collection_authors, show_collection_articles_count
Articlesarticles_style, article_card_corner_style, content_tabs_style, article_footer_variant, table_of_contents_position, show_table_of_contents, show_article_icons, show_article_descriptions, show_article_authors, show_related_articles, show_breadcrumb_icon, show_article_publish_date, show_article_page_author
Feedbackshow_article_feedback_form, require_email_for_article_feedback, feedback_reaction_style (emoji or thumbs), feedback_question_label, feedback_comment_mode
Side menuaside_menu_expansion_mode, show_aside_menu_article_icons, show_aside_menu_collection_icons
Footerfooter_layout (compact, standard or multi_level), footer_shape_type, footer_links, footer_link_translations, footer_text_translations, social_media_links, social_link_translations
Contact buttonshow_contact_us_button, contact_us_custom_link, contact_us_button_position (header or footer)
Badgeshow_powered_by_badge

Links are objects with a title and a url. Footer link groups are objects with a title and a links list. Translations are objects with a locale and the translated links, groups or value.

Plan limits

FieldsPlan feature needed to change them
show_powered_by_badgeRemove branding. See How to remove the Powered by Notiondesk badge
theme, header_shape_type, instant_search, segmented_search_results, ai_search_display_mode, ai_search_aside_position, show_article_publish_date, show_article_page_author, the feedback fields, the side menu fields, the footer fields, the social links and the contact button fieldsAdvanced customization

Changing one of them on a plan without the feature answers 403 permission_denied, the message names the feature, and nothing is written.

Without advanced customization, the footer colors keep their stored value with no error. Without an enabled AI chatbot, ai_search_display_mode, ai_search_aside_position and ai_search_enabled: true also keep their stored value.

List limits

  • Each list holds up to 100 entries, and so does each links or groups list inside it.
  • All lists together hold up to 3,000 entries, counting nested entries and the stored lists your body leaves out.

The contact button turns the contact form on

While show_contact_us_button is true on a plan with advanced customization, every branding update turns the help center's contact form on, as a save in the dashboard does. See the contact form section of Update help center settings with the Notiondesk API.

Choose a theme

curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/themes" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16"
{
  "object": "list",
  "data": [
    {
      "code": "ocean",
      "name": "Ocean",
      "description": "A calm, airy theme",
      "preview_image_url": "https://example.com/ocean.png",
      "layout": "default"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

The list always holds every theme in one response, in display order. Apply one by sending its code as theme:

curl -i -X PATCH "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/settings/customize" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16" \
  -H "Content-Type: application/json" \
  -d '{"theme": "ocean"}'

Setting a theme needs advanced customization. Sending "theme": null leaves the theme unchanged.

Errors

StatuscodeWhen
400validation_errorThe body names a dashboard-only field, a value is not one of the field's choices, a color is not #rrggbb, a required value is null, a list is too long, theme names no theme, or the body has an unknown field
403insufficient_scopeThe key lacks the read scope, or admin for the update
403permission_deniedThe update changes a field your plan does not include, or the key's creator cannot change this help center
404not_foundThe help center does not exist in your workspace

Field errors name the value, for example colors.primary or footer_links[0].links. See Handle Notiondesk API errors, rate limits, and retries.

Common questions

Can I upload a logo with the Notiondesk API?

No. Logos, the favicon and header images are set in the dashboard.

Can I change custom CSS or JavaScript with the API?

No. Custom CSS and custom JavaScript are dashboard-only, and the API never reads or changes them.

Why does my update answer 403 on a field I did not change?

You sent a value that differs from the stored one on a field your plan does not include. Read the branding first and send the stored value back, or leave the field out.

Does a branding update need a sync?

No. The update refreshes the whole help center by itself.

What's next

Related articles

Was this page helpful?

Still need help? Ask us