# Branding Source: https://docs.native.no/native-api/branding > **Preview.** The Native API is not live yet. This page describes the planned interface; names and fields can change before access opens. Read a brand’s colours, fonts and logos, and change them. A change applies to new posts only: nothing already made is drawn again. > **Not live for partners yet.** Partner access to the Native API is not live. Partner sign-in with client credentials and the versioned endpoint `/mcp/v1` are still in development. All three tools on this page are in development: they are not deployed, and their names and fields can still change. A brand’s look is what Native draws its posts with: a palette of colours, which colour plays which role, a heading font, a body font and a logo. The tools on this page read that look and change it, one brand at a time. They use the same code as the Design style settings in the Native app. A change you make here is the change a person would make there. When Native builds a profile from a website, it reads the look from the site. So read the style first with `get_brand_style`, then change only what is wrong. ## Existing posts keep their look Nothing on this page draws an existing post again. That includes approved and scheduled posts. Only posts made after the change carry the new colours, fonts or logo. This is on purpose: a post should publish the way it was approved. ## Design style Colour roles, the heading and body fonts, the logo setting for posts and the style guide all come from the brand’s Design style. Each save makes a new version of it. Older versions are kept, and a change can be undone from Design style in the Native app. `designStyle` in `get_brand_style` says where a brand stands: | `designStyle` | What it means | What you can change | | --- | --- | --- | | `active` | The brand has a Design style. | Everything on this page. | | `not_set_up` | There is no Design style version yet. `colorRoles` and `styleGuide` are `null`, and so are the heading and body fonts. | Everything. The first `update_brand_style` that sets a role or a font creates the first version. | | `disabled` | The brand is not on Design style. Its posts are drawn from the plain palette. | Palette colours and logos. Roles and fonts are refused with `design_style_unavailable`. | | `unreadable` | The brand has a Design style, but Native cannot read it. | Palette colours and logos. Roles and fonts are refused with `design_style_unavailable`. | ### Colour roles Each role holds one colour from the palette, or `auto`. With `auto`, Native picks a colour from the palette for each post. | Role | Used for | Accepts | | --- | --- | --- | | `background` | The canvas behind a post. | A `#RRGGBB` hex or `auto`. | | `accent` | Highlights and buttons. | A `#RRGGBB` hex, `auto` or `none`. | | `text` | The text on a post. With `auto`, Native picks dark or light text by contrast with the background. | A `#RRGGBB` hex or `auto`. | | `secondary` | Supporting details. | A `#RRGGBB` hex, `auto` or `none`. | `none` means the brand has no colour in that role. Only `accent` and `secondary` can be empty. ## Read a brand’s style MCP tool `get_brand_style` (in development) Returns the brand’s palette, its colour roles, its fonts and font library, its logos, how the logo goes on posts, and a summary of its Design style. Reading changes nothing. Arguments: - `brandId` (string, required): The brand, as a UUID. Result data: - `brandId` (string, required): The brand. - `brandName` (string, required): The brand’s name. - `designStyle` (string, required; one of: `active`, `not_set_up`, `disabled`, `unreadable`): Whether the brand has a Design style. See [Design style](https://docs.native.no/native-api/branding#design-style). - `colors` (object[], required): The palette, oldest colour first, each with the roles it plays. - `id` (string, required): The colour’s id. - `hex` (string, required): The colour as a hex code, such as `#B5532A`. - `name` (string | null, required): The colour’s name, when it has one. - `roles` (string[], required; one of: `background`, `accent`, `text`, `secondary`): The roles this colour plays. Empty when it plays none. - `colorRoles` (object | null, required): Which colour plays which role. `null` unless `designStyle` is `active`. - `background` (object | string, required): The colour as `{ hex, name }`, or `auto` when Native picks one for each post. - `accent` (object | string, required): The colour as `{ hex, name }`, `auto`, or `none` for no accent. - `text` (object | string, required): The colour as `{ hex, name }`, or `auto`. - `secondary` (object | string, required): The colour as `{ hex, name }`, `auto`, or `none` for no secondary colour. - `fonts` (object, required): The fonts posts are set in, and the library they come from. - `heading` (string | null, required): The heading font family, or `null` when none is set. - `body` (string | null, required): The body font family, or `null` when none is set. - `library` (object[], required): Every font family the brand has. A role can name any of them. - `id` (string, required): The family’s id. - `name` (string, required): The family’s name, such as `Playfair Display`. - `type` (string | null, required): Where the family comes from, such as `GOOGLE` or `CUSTOM`. - `logos` (object[], required): The brand’s saved logos. The primary logo comes first, then the newest. - `id` (string, required): The logo’s id. - `url` (string, required): A public URL of the file. It does not expire. - `filename` (string, required): The file name. - `description` (string | null, required): What the logo is for, such as "For dark backgrounds". - `isPrimary` (boolean, required): `true` for the logo Native uses in images and ads. - `primaryLogoUrl` (string | null, required): The logo Native puts in images and ads: the primary saved logo, or else the logo it read from the website. `null` when the brand has no logo. - `logoOnPosts` (object, required): How the logo goes on posts. - `frequency` (string, required; one of: `always`, `sometimes`, `never`): How often a post carries the logo. Always `never` when the brand has no logo. - `placement` (string, required): Where the logo goes. `auto` lets Native find a place on each post. The fixed places today are `top-left`, `top-center`, `top-right`, `bottom-left`, `bottom-center` and `bottom-right`. - `logoId` (string | null, required): The id of the saved logo the Design style picked for posts. It can be the primary logo itself. `null` when no file is picked and posts follow whichever logo is primary. - `styleGuide` (object | null, required): A summary of the Design style, as Native gives it to the models that draw posts. `null` unless `designStyle` is `active`. - `styleType` (string | null, required): The kind of picture the brand’s posts use, such as `illustration`, `template` or `typography`. `null` when Native chooses for each post. - `moodTags` (string[], required): Words for the mood of the brand’s posts. - `aestheticTags` (string[], required): Words for their look. - `personalityNote` (string, required): A free note on the brand’s personality. - `styleNote` (string | null, required): A free note on the visual style, when there is one. - `rules` (string[], required): The brand’s design rules, word for word. Result data: ```json { "brandId": "3f6c2a9e-8b1d-4c57-9e0a-2d4b7f1c8a63", "brandName": "Harbour Street Bakery", "designStyle": "active", "colors": [ { "id": "6a1f0c3e-2b7d-4d95-8e41-5c9a7b2d0f18", "hex": "#F4EDE1", "name": "Flour cream", "roles": [ "background" ] }, { "id": "9c4e2a71-0b3f-4f6d-a8e5-7d1b3c9f2e46", "hex": "#B5532A", "name": "Crust", "roles": [ "accent" ] }, { "id": "e2b8d5f4-7a19-4c03-9f6e-1a2d4b8c7e93", "hex": "#2B2B2B", "name": "Charcoal", "roles": [ "text" ] } ], "colorRoles": { "background": { "hex": "#F4EDE1", "name": "Flour cream" }, "accent": { "hex": "#B5532A", "name": "Crust" }, "text": { "hex": "#2B2B2B", "name": "Charcoal" }, "secondary": "auto" }, "fonts": { "heading": "Playfair Display", "body": "Inter", "library": [ { "id": "1b7e4c2d-9a3f-4e51-b6d8-0c2f7a9e3d15", "name": "Playfair Display", "type": "GOOGLE" }, { "id": "8d2a6f1c-4b9e-4a07-93c5-e7f1b2d4a6c8", "name": "Inter", "type": "GOOGLE" } ] }, "logos": [ { "id": "5e9c1a7b-2d4f-4b83-a6e0-3f8b1c5d7a29", "url": "https://storage.googleapis.com/example-bucket/logos/harbour-street-logo.png", "filename": "harbour-street-logo.png", "description": null, "isPrimary": true } ], "primaryLogoUrl": "https://storage.googleapis.com/example-bucket/logos/harbour-street-logo.png", "logoOnPosts": { "frequency": "sometimes", "placement": "auto", "logoId": null }, "styleGuide": { "styleType": "template", "moodTags": [ "warm", "homely" ], "aestheticTags": [ "natural light", "hand lettering" ], "personalityNote": "A neighbourhood bakery that talks like the person behind the counter.", "styleNote": null, "rules": [ "Show bread on wooden boards, never on white plates." ] } } ``` Errors: only the common ones. See [Errors](https://docs.native.no/native-api/errors). ## Change colours and fonts MCP tool `update_brand_style` (in development) Adds colours to the palette, sets which colour plays which role, and sets the heading and body fonts. It changes data, so the token needs the `mcp:write` scope. - Send only what changes. Everything you leave out stays as it is. A call must name at least one palette colour, role or font. - `palette` only adds colours. It never removes or renames one. A hex the palette already has keeps its own name. - A role set to a hex the palette does not have adds that hex to the palette. - A font can be any family in the brand’s font library, or any Google Fonts family. A Google family the library does not have is added to it first, under Google’s own spelling. - Roles and fonts from one call are saved together, as one new Design style version. - It replaces the colours and fonts the brand had in those roles. If your client chose them, check with them before you change them. Arguments: - `brandId` (string, required): The brand, as a UUID. - `palette` (object[], optional): Colours to add to the palette. Up to 20. - `hex` (string, required): A six-digit hex code with its `#`, such as `#6E8B74`. - `name` (string, optional): A name for the colour. Up to 100 characters. Ignored when the palette already has the hex. - `colors` (object, optional): The roles to change. Send only the roles that change. - `background` (string, optional): A `#RRGGBB` hex, or `auto`. - `accent` (string, optional): A `#RRGGBB` hex, `auto`, or `none` for no accent. - `text` (string, optional): A `#RRGGBB` hex, or `auto` for dark or light text by contrast with the background. - `secondary` (string, optional): A `#RRGGBB` hex, `auto`, or `none` for no secondary colour. - `fonts` (object, optional): The fonts to change. - `heading` (string, optional): The heading font family. 1 to 200 characters. A family in `fonts.library`, or a Google Fonts family. - `body` (string, optional): The body font family. 1 to 200 characters. A family in `fonts.library`, or a Google Fonts family. The result data is the brand’s style as it now reads, in the same shape as `get_brand_style`, with one more field: Result data, added to the style: - `updated` (object, required): What this call changed. - `colorsAdded` (string[], required): The hex codes this call added to the palette. Empty when it added none. - `fontsAdded` (string[], required): The font families this call added to the library from Google Fonts. - `designStyle` (string, required; one of: `saved`, `unchanged`, `not_requested`): `saved`: a new Design style version was saved. `unchanged`: the roles and fonts you sent were already set, so no version was saved. `not_requested`: the call set no role and no font. This call adds a sage green to the palette, makes it the secondary colour, and sets a new heading font from Google Fonts: Arguments: ```json { "brandId": "3f6c2a9e-8b1d-4c57-9e0a-2d4b7f1c8a63", "palette": [ { "hex": "#6E8B74", "name": "Sage" } ], "colors": { "secondary": "#6E8B74" }, "fonts": { "heading": "Fraunces" } } ``` Part of the result data: ```json { "updated": { "colorsAdded": [ "#6E8B74" ], "fontsAdded": [ "Fraunces" ], "designStyle": "saved" } } ``` ### Errors | Code | `retryable` | What it means | | --- | --- | --- | | `font_not_found` | `false` | A font you named is neither in the library nor a Google Fonts family. Nothing changed. `invalidFields` names `fonts.heading`, `fonts.body` or both. Use a name from `fonts.library`, or the family name as Google Fonts spells it. | | `design_style_unavailable` | `false` | The brand is not on Design style, or its Design style cannot be read, so it cannot take roles or fonts. Nothing changed. A call that sends only `palette` still works. | | `design_style_busy` | `true` | Another save landed at the same moment, or Native was still setting the Design style up. Roles and fonts were not set. Palette colours and library fonts the call added stay. Call again with the same arguments in a few seconds. | | `bad_request` | `false` | The call names no change at all, or a value is not one Native accepts. When a field is at fault, `invalidFields` names it. | If Native cannot reach Google Fonts to look up a font, the call fails with `internal_error`. The same call can succeed a little later. Of the codes in the table, only `design_style_busy` is worth sending again unchanged. A short wait between tries is enough: Retry a busy save: ```ts async function updateBrandStyle(args: Record) { for (let attempt = 1; attempt <= 3; attempt++) { const result = await client.callTool({ name: "update_brand_style", arguments: args }); const data = (result.structuredContent as { data: any }).data; if (!result.isError) return data; if (data.error.code !== "design_style_busy") throw new Error(data.error.code); await new Promise((resolve) => setTimeout(resolve, 3_000 * attempt)); } throw new Error("design_style_busy"); } const style = await updateBrandStyle({ brandId: "3f6c2a9e-8b1d-4c57-9e0a-2d4b7f1c8a63", colors: { accent: "#B5532A", secondary: "none" }, }); console.log(style.updated.designStyle); ``` ## Upload a logo MCP tool `upload_brand_logo` (in development) Saves a logo for the brand. By default it also becomes the primary logo: the one Native uses in images and ads. It changes data, so the token needs the `mcp:write` scope. - Send the file one of two ways: a public https URL in `sourceUrl`, which Native fetches, or the file itself in `dataBase64` with its `contentType`. Send exactly one of them. - The logo it replaces stays among the brand’s logos. - Posts and ads already made keep the logo they were made with. - An SVG is stored as a PNG. Arguments: - `brandId` (string, required): The brand, as a UUID. - `sourceUrl` (string, optional): A public https URL of the logo file. Native fetches it. Up to 2,048 characters. Send this or `dataBase64`, not both. - `dataBase64` (string, optional): The file as standard base64, with `+`, `/` and `=` padding. Line breaks are fine. base64url is refused. Up to 11 MiB of characters, which is an image of about 8 MiB. Needs `contentType`. - `contentType` (string, optional; one of: `image/png`, `image/jpeg`, `image/webp`, `image/gif`, `image/svg+xml`): Required with `dataBase64`. The bytes must be the type you name. - `filename` (string, optional): A name for the file. Up to 120 characters. Native gives it the extension of the stored file. `logo` when you leave it out. - `description` (string, optional): What this logo is for, such as "For dark backgrounds". Up to 1,000 characters. - `primary` (boolean, optional; default: `true`): Make this the logo Native uses in images and ads. `false` saves an extra variant and leaves the primary logo as it is. If the brand has no primary logo yet, the new logo becomes primary even with `false`. Result data: - `brandId` (string, required): The brand. - `logo` (object, required): The saved logo, in the same shape as `logos[]` in `get_brand_style`. - `id` (string, required): The logo’s id. - `url` (string, required): A public URL of the stored file. It does not expire. - `filename` (string, required): The file name. - `description` (string | null, required): The description you sent, or `null`. - `isPrimary` (boolean, required): Whether this is now the primary logo. - `madePrimary` (boolean, required): Whether this call made the logo the primary one. - `primaryLogoUrl` (string | null, required): The logo Native now puts in images and ads. - `logoOnPosts` (object, required): How the logo goes on posts, in the same shape as `logoOnPosts` in `get_brand_style`. - `frequency` (string, required; one of: `always`, `sometimes`, `never`): How often a post carries the logo. - `placement` (string, required): Where the logo goes, such as `auto` or `bottom-right`. - `logoId` (string | null, required): The saved logo the Design style picked for posts, or `null` when posts follow the primary logo. > **A new primary logo may not reach posts.** The Design style can pick one saved logo for posts. When it does, `logoOnPosts.logoId` names that logo, and new posts keep using it after you upload a new primary logo. None of the tools on this page changes that pick, so tell your client which logo their posts will carry. Arguments: ```json { "brandId": "3f6c2a9e-8b1d-4c57-9e0a-2d4b7f1c8a63", "sourceUrl": "https://www.harbourstreetbakery.example/assets/logo-light.svg", "description": "For dark backgrounds", "primary": false } ``` Result data: ```json { "brandId": "3f6c2a9e-8b1d-4c57-9e0a-2d4b7f1c8a63", "logo": { "id": "b3d7f2a9-6c1e-4f08-8a5d-2e9c4b7f1a63", "url": "https://storage.googleapis.com/example-bucket/logos/logo.png", "filename": "logo.png", "description": "For dark backgrounds", "isPrimary": false }, "madePrimary": false, "primaryLogoUrl": "https://storage.googleapis.com/example-bucket/logos/harbour-street-logo.png", "logoOnPosts": { "frequency": "sometimes", "placement": "auto", "logoId": null } } ``` To send the file itself, read it and encode it as base64: Upload a logo from a file: ```ts import { readFile } from "node:fs/promises"; const bytes = await readFile("harbour-street-logo.png"); const result = await client.callTool({ name: "upload_brand_logo", arguments: { brandId: "3f6c2a9e-8b1d-4c57-9e0a-2d4b7f1c8a63", dataBase64: bytes.toString("base64"), contentType: "image/png", filename: "harbour-street-logo.png", }, }); const data = (result.structuredContent as { data: any }).data; if (result.isError) { // "logo_unreadable" when the file is not a usable image throw new Error(data.error.code); } if (data.logoOnPosts.logoId && data.logoOnPosts.logoId !== data.logo.id) { // Posts keep the logo the Design style picked for them. } ``` ### Errors | Code | `retryable` | What it means | | --- | --- | --- | | `logo_unreadable` | `false` | The file is not a usable logo. It is not an image at least 16 px each way, it failed the upload scan, or it could not be fetched from `sourceUrl`. A download that fails, answers with something other than an image, or redirects to a private address counts as not fetched. Nothing was saved. `invalidFields` names `sourceUrl` or `dataBase64`. | | `source_not_https` | `false` | `sourceUrl` is not https. Nothing was fetched. Send the same address as https. | | `source_not_public` | `false` | `sourceUrl` itself points at a private or internal address. Nothing was fetched. Use an address anyone on the internet can reach. | | `bad_request` | `false` | `contentType` is not one of the five types, `dataBase64` is not valid base64 or is empty, the decoded file is over 8 MiB, or the bytes are not the type `contentType` names. | If Native cannot scan or store the file, the call fails with `internal_error` and nothing is saved. The same call can then succeed. ## Other errors Every tool on this page can also return the errors any tool can: `bad_request`, `not_found`, `forbidden`, `subscription_required`, `internal_error`, `upstream_timeout`, `upstream_unavailable`, `upstream_identity_failed`, `identity_provider_unavailable` and `upstream_`. `update_brand_style` and `upload_brand_logo` can return `writes_disabled`. [Errors](https://docs.native.no/native-api/errors) explains each one.