Design

A design is the white-label theme applied to your team's public passports — the pages a QR code resolves to. Colours, corner rounding, shadow depth, logo, fonts, the page's structural style, how each kind of value is drawn and how each part of the page is styled (the top bar, the masthead, the chapters, the cards, the tables, the figures, the charts, the spacing): everything a visitor sees that is yours rather than Synex's.

There is exactly one design per team, and it is addressed without an id. A key is pinned to one team and a team has one theme, so there is nothing for an id to disambiguate — /v1/design is the whole address. A composition can override any of it, but the logo, for the passports of one ontology.

The abilities are the whole gate

Neither design:read nor design:write is in a key's default ability set — grant them explicitly when you mint the key.

They are non-default for a reason worth stating plainly: a key minted to write passport values has no business restyling every public passport the team has ever released. One careless grant turns a data integration into something that can repaint the customer-facing surface of the whole product line.

There is deliberately no gate beyond the ability. In the Synex application a member edits branding if their role grants design:write — the default Editor role does — and a key is capped by what its owner may currently do, so asking more of the key here would make the API stricter than the surface it mirrors. A rule that only exists on one of two equivalent paths is not a security boundary, just a difference to work around.

The design model

Twenty-six settings beside the object discriminator: the five original ones (palette, rounding, shadow, logo, font), thirteen that shape the page's structure, colours, type and components (see Presets, colour modes and components), and the eight part-style blocks. Null means "not set", and a setting that is not set inherits (see Resolution order).

  • Name
    object
    Type
    string
    Description

    Always design.

  • Name
    palette
    Type
    array
    Description

    An ordered colour scale of { lightness, hex } entries, step 50 first. [] when unset. At most 32 entries; the renderer reads the first 11.

  • Name
    rounding
    Type
    integer
    Description

    Corner-rounding level, 1–6. Nullable.

  • Name
    shadow
    Type
    integer
    Description

    Shadow-depth level, 1–6. Nullable.

  • Name
    logo
    Type
    string
    Description

    A file_ id from your team's Drive. Nullable.

  • Name
    font
    Type
    string
    Description

    The body font, a family from the font catalogue. Nullable.

  • Name
    preset
    Type
    string
    Description

    The passport's structural style: standard, editorial, technical or soft. The default for every setting left null. Nullable; null reads as standard.

  • Name
    mode
    Type
    string
    Description

    simple or advanced: whether the advanced settings apply. Nullable.

  • Name
    color_mode
    Type
    string
    Description

    simple generates every colour from palette; advanced uses colors. Nullable.

  • Name
    appearance
    Type
    string
    Description

    A light or a dark page. Nullable; null follows the preset.

  • Name
    colors
    Type
    object
    Description

    The advanced-mode colours: background, text, muted, rule, surface and accent, each #rrggbb (read back in lower case) or null. null when no role is set.

  • Name
    font_heading
    Type
    string
    Description

    The face for names, chapter titles and card titles, from the catalogue. Nullable; null follows the preset, then font.

  • Name
    font_figures
    Type
    string
    Description

    The face for numbers, measurements and identifiers, from the catalogue. Nullable; null follows the preset, then font.

  • Name
    labels
    Type
    string
    Description

    How field labels and small headings are set: muted, caps or strong. Nullable.

  • Name
    navigation
    Type
    string
    Description

    One long page of numbered chapters, or a strip of tabs. Nullable.

  • Name
    hero
    Type
    string
    Description

    How the product image and the name open the page: split, banner, compact or centered. Nullable.

  • Name
    frames
    Type
    string
    Description

    Cards on hairline rules (open) or in framed surfaces. Nullable.

  • Name
    components
    Type
    object
    Description

    The default display style of each of the seven kinds of value. null when no kind is set.

  • Name
    component_options
    Type
    object
    Description

    Design-wide display defaults per kind; only image has options. null when no option is set.

  • Name
    top_bar
    Type
    object
    Description

    The top bar: layout, logo size and which parts show.

  • Name
    masthead
    Type
    object
    Description

    The masthead: title size, key figures, the product image and which parts show.

  • Name
    chapters
    Type
    object
    Description

    The chapter headers, the chapter index and the tabs.

  • Name
    sections
    Type
    object
    Description

    The card headers and the gallery's columns.

  • Name
    fields
    Type
    object
    Description

    The rows of field lists and children tables.

  • Name
    figures
    Type
    object
    Description

    The stat grids and key figures.

  • Name
    charts
    Type
    object
    Description

    The charts' colours, grid, legend and bars.

  • Name
    rhythm
    Type
    object
    Description

    The spacing between chapters and cards, and the content's width.

The eight part-style blocks are objects even when nothing is set: every leaf is there, null until set.

palette is an ordered scale, not a bag of settings

The array's position carries meaning: entry 0 is step 50, entry 5 is step 500 and entry 10 is step 950. The renderer reads entry 5 as the brand colour. It builds the page background from step 50 blended toward white, or, on a dark page, from step 950 blended toward black; the other steps give the text, the shades between and the chart colours. Reordering the entries restyles the passport even though every colour in it is unchanged, so treat the palette as a scale you author top to bottom rather than as a set of named options you can shuffle.

Each entry is {lightness, hex} — lightness on the familiar 50/100/200/…/900/950 scale, and hex as #RRGGBB. The Synex application writes 11 entries; at most 32 are accepted, and the renderer reads the first 11.

Send all 11 steps. A palette with fewer usable entries (a 50…900 scale, a single colour, an entry whose hex is null) is completed rather than ignored: each usable entry keeps its position, and the others are filled from the brand scale of the usable entry nearest step 500 (entry 5 itself when it is usable; between two equally near, the darker). Position decides the step, with one exception: a palette of a single entry that carries a lightness is the step it names, so {"lightness": 500, …} is the brand colour and the scale is built around it. A single entry without one is step 50, so the brand scale is built from that colour and the page takes a tint of it. A palette with no usable entry draws in a neutral slate.

rounding and shadow are levels, not measurements

Both are integers from 1 to 6, and both index the renderer's own class maps. rounding: 3 is not "3px" and shadow: 2 is not a blur radius — they select the third and second steps of scales the renderer defines. Move them a step at a time and look at the result; there is no unit to compute with.

The font catalogue

font is the body font; font_heading and font_figures take the same values. A font is one of 24 families, and the viewer loads them from Synex's own servers, never from a third party.

CategoryFamilies
SansInter, Roboto, Open Sans, Nunito, Poppins, Work Sans, DM Sans, IBM Plex Sans
SerifMerriweather, Playfair Display, Lora, Crimson Pro, Cormorant Garamond, Source Serif 4
MonoFira Code, JetBrains Mono, Source Code Pro, DM Mono, IBM Plex Mono
DisplayArchivo, Montserrat, Bebas Neue, Oswald, Raleway

A PATCH matches a family without case and without regard to hyphens, underscores or spaces between words, and stores the catalogue's own spelling: montserrat and bebas-neue are stored as Montserrat and Bebas Neue. A family outside the list is 400 parameter_invalid ("Pick a font from the list.").

Older teams stored fonts free-form, and the Synex Design page used to store lower-case slugs, so a stored value is read the same way: one that matches the catalogue comes back in its canonical spelling, and one that does not comes back as null. A PATCH of any setting writes the design back in that normalised form, so it also clears a stored font that is outside the catalogue.

An unset design reads as null, not as a default

A team that has never set a theme gets palette: [], null for every other setting and the eight blocks as objects of nulls — the Unset response under Retrieve the design. Those nulls mean "not set", not "set to the default". The renderer's own fallbacks decide what an unthemed passport looks like, and reporting those fallbacks here would claim the team had picked something it never picked — which is exactly the claim that breaks the moment the renderer's defaults change.

If you are mirroring a design into your own system, carry the nulls through rather than substituting values for them.

logo is an id, not a link

GET /v1/design returns the logo's file id and stops there. To get the bytes, turn it into a link yourself with GET /v1/files/{file}/download.

A presigned URL is a bearer credential with a clock on it. Minting one on every read of the theme would hand you a signature you did not ask for, on every poll, that you could not cache for longer than its own short lifetime — and it would put a signing round-trip inside a call that is otherwise a single cheap read.

Presets, colour modes and components

The thirteen settings below describe a passport's structure, colours, type and components. Every one of them is nullable, and null means "inherit" (see Resolution order). The eight part-style blocks have a section of their own, Part styles.

SettingValuesWhat it decides
presetstandard, editorial, technical, softThe passport's structural style, and the default for every setting left null. Null reads as standard.
modesimple, advancedWhether the advanced settings apply at all (see The mode).
color_modesimple, advancedsimple generates every colour from palette, for the appearance. advanced uses colors.
appearancelight, darkA light or a dark page. Null reads as the preset's.
colorsan object of six rolesThe advanced-mode colours: background, text, muted, rule, surface, accent.
font_headinga catalogue familyThe face for names, chapter titles and card titles. Null follows the preset, then the body font.
font_figuresa catalogue familyThe face for numbers, measurements and identifiers. Null follows the preset, then the body font.
labelsmuted, caps, strongField labels and small headings in the muted colour, in capitals, or in sentence case at weight 600 in the text colour. Null follows the preset.
navigationchapters, tabsOne long page of numbered chapters, or a tab strip.
herosplit, banner, compact, centeredHow the product image and the name open the page. centered is one centred column with the key figures in a row and the image below.
framesopen, framedCards on hairline rules, or in framed surfaces. rounding and shadow apply to framed surfaces.
componentsan object of seven kindsThe default display style of each kind of value.
component_optionsan object of options per kindThe design-wide display defaults of a kind of value. Only image has options.

Presets

A preset is a structural style: heading weight, corner shape and spacing live in the viewer's stylesheet and follow the preset. It also supplies a default for each setting you leave null; for labels that is caps on editorial and technical, and muted on standard and soft.

PresetCharacter
standardThe team's font for every face, a split hero, open frames, a light page and the team's rounding.
editorialCormorant Garamond headings over DM Sans, square corners, plain images.
technicalA dark page with DM Sans and JetBrains Mono for figures and identifiers, square corners, framed images.
softDM Sans throughout, a banner hero, round corners and pill-shaped chips, card files and badge yes/no values.

A preset sets no part-style leaf: every block leaf defaults to the value in the part-style tables, whichever preset is chosen. The exceptions are the masthead's image_side, image_corners and image_fit, whose defaults follow the hero layout (a null hero takes the preset's) and, for image_fit, the preset itself.

Presets never set colours; colours come from palette or colors. Choosing a preset in the Synex application also writes the preset's fonts, rounding and appearance into the design, so you can see and change each, and leaves the hero, the component styles and every part style alone. The API does not write any of them: PATCH {"preset": "technical"} changes preset and nothing else, and the settings you left null follow the preset when a passport is drawn.

Colour modes

In simple mode the viewer generates the six colour roles from palette, for the appearance, and holds them to its contrast rules: text on the background at 12:1 or better, muted text at 4.5:1 or better on the background, on surfaces and on framed cards. colors is ignored.

In advanced mode colors is used as given. A role left null is derived: the background and text from the palette, the muted, rule and surface colours from the text and background, and the accent from the palette's brand colour. So you can set only background and accent.

Components

components sets how each kind of value is drawn by default. A kind is a group of property types, and a style is one way of drawing it:

KindProperty typesStyles
imageimageplain, captioned, framed, file
filefilerow, card, button, link
figurenumber, measurementfigure, inline, meter, ring
booleanbooleantext, badge
tagstagschips, outline, list
long_textlong textparagraph, lead, collapsed
rangerangetrack, text

Short text and date values have one look and no kind. A figure left null is drawn as a large figure in a stat grid and as an inline value elsewhere. An image or file value with no link is not drawn as a broken image or a dead download.

A single placement can override its kind's default with its own display: see Compositions.

Component options

component_options sets how every value of a kind is displayed, the way a placement's display_options set it for one value: in the passport's sections and among the masthead's key figures. Only image has options. The masthead's product image is styled by the masthead block's image_ leaves instead.

OptionValuesDefaultWhat it does
aspectoriginal, 1:1, 4:3, 3:2, 16:9originalThe shape of every image a placement does not shape itself; original keeps the image's own.
fitcover, containcoverFill the shape and crop, or show the whole image. Applies only to an image with a shape (an aspect other than original).
cornerssquare, rounded, extraby styleNone; the design's rounding (its inner radius on every picture, its full radius on the framed card); or twice the design's rounding and at least 1.5rem. Null keeps each style's own: plain square, the others rounded.
backdropsurface, none, tint, whitenoneWhat shows around a contained image or behind a transparent one: the surface colour, nothing, the accent washed out, or white in both appearances.

aspect, fit and backdrop apply to the plain, captioned and framed styles; the file style ignores all three, and only corners reaches its thumbnail. A placement's display_options win, key by key: a placement that sets its own aspect keeps it and still takes the design's fit when it sets none. corners and backdrop come from the design alone, and width stays a placement option.

component_options reads back as null until an option is set, and then with every option, null for those not set:

{ "component_options": { "image": { "aspect": "4:3", "corners": "rounded" } } }

Resolution order

Each setting is resolved separately, for every passport, from the first of these that is not null:

  1. the composition's design block,
  2. the team's design, this resource,
  3. the preset's default, where the preset is itself resolved composition first, then team, then standard,
  4. the viewer's default (for font_heading and font_figures, the resolved body font).

components resolves per kind, component_options per option (with no preset step) and each part-style block per leaf (and per show part) in the same order, and a placement's own display and display_options sit above all of them. In simple mode the advanced settings skip steps 1 and 2 and resolve from the preset alone (see The mode).

Part styles

Eight objects restyle one part of the passport each: top_bar, masthead, chapters, sections, fields, figures, charts and rhythm. Every leaf is nullable and null inherits, leaf by leaf, in the resolution order. The Default column is what an unset leaf draws, which is the passport as it has always looked: nothing changes until you set a leaf. A show object holds one true or false per part and null to inherit; every part shows by default.

The mode

mode decides whether the advanced settings apply. In simple the passport resolves color_mode, colors, font_figures, labels, hero, frames, shadow, components, component_options and every part-style leaf from the preset alone and ignores what is stored; in advanced every layer applies. Switching never deletes a value, so going back to advanced brings the stored ones back.

Each design, the team's and each composition's, has its own mode: the mode it stores, or, when that is null, advanced if it stores an advanced setting. An advanced setting is any of those listed above but shadow and font_figures (every older save stores a shadow, and picking a preset writes the figures face). A composition's mode wins over the team's, and only a winning simple gates anything:

  • A composition that sets frames, hero, components, a part style or another advanced setting is advanced unless it says mode: "simple", even over a team in simple, and its settings apply. Like a composition set to advanced, it also brings back the advanced values the team has stored.
  • A composition with no advanced setting and no mode follows the team's mode.
  • A design with no mode and no advanced setting gates nothing.

A PATCH that sets an advanced setting and no mode (left out or null) stores mode: "advanced", so what you set is what a reader sees. To store an advanced value while the team stays in simple, send mode: "simple" in the same body. The Synex Design page writes the mode it shows on every save: the one the person chose, else the one this section infers.

top_bar

LeafValuesDefaultWhat it does
layoutoverlay, solid, floatingoverlayTransparent over the masthead and a translucent surface once scrolled; the surface and a rule from the start; an inset bar with the design's rounding and a shadow.
logo_sizes, m, lmThe height of the logo.
showlogo, qr, language, audience, identityall shownidentity is the name, reference and status that appear once the page scrolls. Hiding audience leaves the ?audience= link working.

masthead

LeafValuesDefaultWhat it does
title_sizes, m, l, xllThe size of the product name; l is the size each hero layout starts from.
figuresruled, plain, tilesruledKey figures with a rule above each, bare, or each on a surface of its own.
image_sidestart, endend for centered, else startThe side the product image sits on: left or right for split and compact, above or below the text for banner and centered. On a phone split and compact keep the image first whatever the side.
image_sizes, m, lmThe size of the product image; m is the size each layout has always drawn.
image_framebleed, insetinset for compact and centered, else bleedA split or banner image to the page edge, or inset from it, where it takes image_corners. compact and centered always inset the image.
image_cornerssquare, rounded, extrarounded for centered and an inset split or banner, else squareThe corners of an inset image: none, the design's rounding, or twice it and at least 1.5rem. A bleed image has none.
image_fitcover, containcontain for compact, centered and the technical and soft presets, else coverFill the frame and crop, or show the whole product.
image_focuscenter, top, bottom, left, rightcenterWhere a filled image is anchored when it is cropped. Ignored with contain.
image_backdropsurface, none, tint, whitesurfaceBehind a contained or transparent product: the surface colour, nothing, the accent washed out, or white in both appearances.
showlogo, ids, status, figures, image, exploreall shownids is the reference and passport ID line; status the status, date and tier badges; explore the "Explore the passport" link. Hiding image makes the layout fall back to text only, and none of the image_ leaves draws.

chapters

LeafValuesDefaultWhat it does
headernumbered, numeral, centered, minimalnumberedA "01 / 04" line with the icon and title and a rule under; the number as a large figure beside the title; number line and title centred over a short accent rule; the title only.
sizes, m, lmThe size of the chapter title.
indexsidebar, strip, hiddensidebarA sticky sidebar on large screens and a sticky strip below them; the strip at every width; or no index. A hidden index leaves every chapter its heading and anchor.
tabsunderline, pillsunderlineWith navigation: tabs, the active tab underlined or drawn as a pill on the accent colour.
shownumber, icon, dividerall shownParts of a chapter header, in any header style.

sections

LeafValuesDefaultWhat it does
headerruled, plain, bar, kickerruledA rule above an open card; no rule; a short accent bar above the title; the title as a small label above the content. The title stays a heading.
sizes, mmThe size of the card title.
gallery_columns"2", "3""3"The columns of a media section's gallery from the large breakpoint; below it the gallery keeps two, and one on a phone. A full-width image spans the columns in effect. A string: the number 2 is refused.
showdescriptionshownThe card's description.

fields

Field lists and the table of a children card. A Field List set to the Timeline style ignores rows and dividers.

LeafValuesDefaultWhat it does
rowssplit, stacked, gridsplitLabel and value in two columns; the label above the value; stacked pairs in two columns from the small breakpoint and three from the large.
dividerslines, zebra, nonelinesA rule between rows; every other row on the surface colour; nothing.
densitycompact, comfortable, roomycomfortableThe vertical padding of a row.

figures

Stat grids and key figures.

LeafValuesDefaultWhat it does
lookgrid, tiles, ruled, plaintiles when frames is framed, else gridRuled cells; each figure in a box; a rule above each figure and no box; the figures alone.
sizes, m, lmThe size of a figure.
unitafter, belowafterThe unit beside the number, or on its own line under it.
cornerssquare, roundedrounded when the look is tiles, else squareWith the grid look rounded rounds the outer frame to the design's rounding and keeps a rule between cells; with tiles it rounds each box. ruled and plain have no box, so they ignore it, and the masthead's key figures keep their own look.

charts

LeafValuesDefaultWhat it does
colorsaccent, multi, monoaccentThe brand accent; seven fixed hues kept legible against the page background; the accent followed by shades of the text colour.
gridlines, nonelinesGrid lines behind a chart.
legendside, below, hiddensideBeside a pie from the small breakpoint; always below; visually hidden but still read by screen readers.
barsrounded, squareroundedThe corners of a bar.

rhythm

LeafValuesDefaultWhat it does
spacingcompact, comfortable, spaciouscomfortableThe gap between chapters and between cards: three quarters of the default, the default, one and a half times it.
widthnarrow, standard, widestandardThe maximum width of the content: 64rem, 80rem or 90rem. The masthead keeps its own frame.

A block replaces wholesale

A block in a PATCH replaces the stored block: a leaf you leave out is unset afterwards. To change one leaf, send the leaves you want to keep with it. A block sent as null or {} clears it, and a block you leave out of the body is untouched.

curl -X PATCH https://api.synexcloud.com/v1/design \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chapters": {"header": "minimal"}}'

curl -X PATCH https://api.synexcloud.com/v1/design \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chapters": {"size": "l"}}'

After the second call chapters.size is l and chapters.header is null: the second body replaced the first. A show object that names one part reads back with the other parts null, and those parts show.


GET/v1/design

Retrieve the design

Reads the team's theme. Requires design:read.

The singleton always exists — a team that has never touched its branding still has a design, one whose every field is null — so this never 404s.

Every setting is present on every read. The eight part-style blocks always come back as objects with every leaf, null for those not set; colors, components and component_options come back as null until something in them is set, and then with every role, kind or option.

Request

GET
/v1/design
curl https://api.synexcloud.com/v1/design \
  -H "Authorization: Bearer $SYNEX_API_KEY"

Response

{
  "object": "design",
  "palette": [
    { "lightness": 50, "hex": "#F5F8FC" },
    { "lightness": 100, "hex": "#E7EEF8" },
    { "lightness": 200, "hex": "#C8D9F1" },
    { "lightness": 300, "hex": "#9CBCE6" },
    { "lightness": 400, "hex": "#6698DA" },
    { "lightness": 500, "hex": "#2F6FED" },
    { "lightness": 600, "hex": "#2459C4" },
    { "lightness": 700, "hex": "#1C459B" },
    { "lightness": 800, "hex": "#153472" },
    { "lightness": 900, "hex": "#0E2450" },
    { "lightness": 950, "hex": "#0A1836" }
  ],
  "rounding": 3,
  "shadow": 2,
  "logo": "file_00a1b2c3d4e5f607",
  "font": "Inter",
  "preset": "technical",
  "color_mode": "simple",
  "appearance": "dark",
  "colors": null,
  "font_heading": "DM Sans",
  "font_figures": "JetBrains Mono",
  "navigation": "chapters",
  "hero": "split",
  "frames": "framed",
  "components": {
    "image": "framed", "file": "row", "figure": null, "boolean": null,
    "tags": null, "long_text": null, "range": null
  },
  "mode": "advanced",
  "labels": "caps",
  "component_options": {
    "image": { "aspect": "4:3", "fit": null, "corners": "rounded", "backdrop": null }
  },
  "top_bar": {
    "layout": "solid", "logo_size": null,
    "show": { "logo": null, "qr": false, "language": null, "audience": null, "identity": null }
  },
  "masthead": {
    "title_size": null, "figures": "tiles",
    "image_side": null, "image_size": null, "image_frame": "inset", "image_corners": null,
    "image_fit": null, "image_focus": null, "image_backdrop": null,
    "show": { "logo": null, "ids": null, "status": null, "figures": null, "image": null, "explore": null }
  },
  "chapters": {
    "header": "numeral", "size": null, "index": null, "tabs": null,
    "show": { "number": null, "icon": false, "divider": null }
  },
  "sections": { "header": null, "size": null, "gallery_columns": "2", "show": { "description": null } },
  "fields": { "rows": null, "dividers": null, "density": null },
  "figures": { "look": null, "size": null, "unit": null, "corners": null },
  "charts": { "colors": null, "grid": null, "legend": null, "bars": null },
  "rhythm": { "spacing": null, "width": null }
}

Unset

{
  "object": "design",
  "palette": [],
  "rounding": null,
  "shadow": null,
  "logo": null,
  "font": null,
  "preset": null,
  "color_mode": null,
  "appearance": null,
  "colors": null,
  "font_heading": null,
  "font_figures": null,
  "navigation": null,
  "hero": null,
  "frames": null,
  "components": null,
  "mode": null,
  "labels": null,
  "component_options": null,
  "top_bar": {
    "layout": null, "logo_size": null,
    "show": { "logo": null, "qr": null, "language": null, "audience": null, "identity": null }
  },
  "masthead": {
    "title_size": null, "figures": null,
    "image_side": null, "image_size": null, "image_frame": null, "image_corners": null,
    "image_fit": null, "image_focus": null, "image_backdrop": null,
    "show": { "logo": null, "ids": null, "status": null, "figures": null, "image": null, "explore": null }
  },
  "chapters": {
    "header": null, "size": null, "index": null, "tabs": null,
    "show": { "number": null, "icon": null, "divider": null }
  },
  "sections": { "header": null, "size": null, "gallery_columns": null, "show": { "description": null } },
  "fields": { "rows": null, "dividers": null, "density": null },
  "figures": { "look": null, "size": null, "unit": null, "corners": null },
  "charts": { "colors": null, "grid": null, "legend": null, "bars": null },
  "rhythm": { "spacing": null, "width": null }
}

PATCH/v1/design

Update the design

Moves only the fields present in the body. Requires design:write. Omit a field and it keeps its stored value; there is no need to read the theme, edit it, and send it back whole. The one field that moves without being sent is mode: an advanced setting sent without one stores mode: "advanced" (see The mode).

palette replaces wholesale. Merging a caller's three entries into a stored eleven would splice two scales together and produce something nobody designed — a brand colour from one palette sitting on a background from another. Send the entire scale, or leave the key out of the body entirely.

colors, components, component_options and the eight part-style blocks replace wholesale for the same reason. Each is a whole object, so a body that names two colour roles leaves the other four unset instead of keeping the stored ones. To change one role, kind, option or leaf, send all the ones you want to keep. One sent as null and one left out read back the same.

Clearing a field

Every setting but palette, rounding and shadow accepts an explicit null to unset it: logo, font, the thirteen newer settings and each part-style block.

The logo must exist

A logo that does not name a file in this team's Drive is rejected with 400 resource_missing and param: "logo". Nothing is written.

It is checked because the failure it prevents is silent and public. A logo pointing at nothing renders as a broken image on every public passport the team has released, and the write that caused it would have returned a 200 that looked exactly like success.

It is a 400 rather than a 404 because of what the request addressed: the /v1/design resource exists and was found; it is the logo parameter that names a missing object.

Values outside the contract

A setting outside its list is 400 parameter_invalid, and nothing is written. param names the setting, or the slot inside an object, and the message lists what is accepted. That covers a preset, mode, color_mode, appearance, labels, navigation, hero or frames that is not in its list, a font outside the catalogue, a colors role that is not one of the six or not #rrggbb (colors.text), a components kind that does not exist (components.video) or a style that is not its kind's (components.image), a component_options kind other than image (component_options.file) or an option or value outside its list (component_options.image.aspect), and a part-style leaf or show part that does not exist or holds the wrong kind of value (chapters.header, masthead.show.ids). Every enum leaf is a string: sections.gallery_columns takes "2", and the number 2 is refused.

An empty body is an error

PATCH /v1/design with {} is 400 parameter_invalid ("Send at least one design setting."), not a no-op success. A body naming no field is a caller mistake — a serializer that dropped its fields, a config object that came back empty — and a 200 would hide it behind a response that looks exactly like the change landing.

It also keeps the change feed honest: no design.updated is emitted for a request that changed nothing.

Optional attributes

  • Name
    palette
    Type
    array
    Description

    The whole colour scale. Replaces, never merges.

  • Name
    rounding
    Type
    integer
    Description

    Corner-rounding level, 1–6.

  • Name
    shadow
    Type
    integer
    Description

    Shadow-depth level, 1–6.

  • Name
    logo
    Type
    string
    Description

    A file_ id from your team's Drive, or null to clear.

  • Name
    font
    Type
    string
    Description

    A catalogue family, matched without case, or null to clear.

  • Name
    preset
    Type
    string
    Description

    standard, editorial, technical or soft. Writes the preset alone.

  • Name
    mode
    Type
    string
    Description

    simple or advanced.

  • Name
    color_mode
    Type
    string
    Description

    simple or advanced.

  • Name
    appearance
    Type
    string
    Description

    light or dark.

  • Name
    colors
    Type
    object
    Description

    The six colour roles, each #rrggbb or null. Replaces.

  • Name
    font_heading
    Type
    string
    Description

    A catalogue family.

  • Name
    font_figures
    Type
    string
    Description

    A catalogue family.

  • Name
    labels
    Type
    string
    Description

    muted, caps or strong.

  • Name
    navigation
    Type
    string
    Description

    chapters or tabs.

  • Name
    hero
    Type
    string
    Description

    split, banner, compact or centered.

  • Name
    frames
    Type
    string
    Description

    open or framed.

  • Name
    components
    Type
    object
    Description

    A style per kind. Replaces.

  • Name
    component_options
    Type
    object
    Description

    { "image": { aspect, fit, corners, backdrop } }. Replaces.

  • Name
    top_bar
    Type
    object
    Description

    A part-style block, as are masthead, chapters, sections, fields, figures, charts and rhythm. Each replaces.

Request

PATCH
/v1/design
curl -X PATCH https://api.synexcloud.com/v1/design \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "color_mode": "advanced",
    "colors": {"background": "#0b1220", "text": "#e6edf7", "accent": "#4f8cff"},
    "components": {"figure": "meter"},
    "charts": {"bars": "square"}
  }'

Response

{
  "object": "design",
  "palette": [
    { "lightness": 50, "hex": "#F5F8FC" },
    { "lightness": 100, "hex": "#E7EEF8" },
    { "lightness": 200, "hex": "#C8D9F1" },
    { "lightness": 300, "hex": "#9CBCE6" },
    { "lightness": 400, "hex": "#6698DA" },
    { "lightness": 500, "hex": "#2F6FED" },
    { "lightness": 600, "hex": "#2459C4" },
    { "lightness": 700, "hex": "#1C459B" },
    { "lightness": 800, "hex": "#153472" },
    { "lightness": 900, "hex": "#0E2450" },
    { "lightness": 950, "hex": "#0A1836" }
  ],
  "rounding": 3,
  "shadow": 2,
  "logo": "file_00a1b2c3d4e5f607",
  "font": "Inter",
  "preset": "technical",
  "color_mode": "advanced",
  "appearance": "dark",
  "colors": {
    "background": "#0b1220", "text": "#e6edf7", "muted": null,
    "rule": null, "surface": null, "accent": "#4f8cff"
  },
  "font_heading": "DM Sans",
  "font_figures": "JetBrains Mono",
  "navigation": "chapters",
  "hero": "split",
  "frames": "framed",
  "components": {
    "image": null, "file": null, "figure": "meter", "boolean": null,
    "tags": null, "long_text": null, "range": null
  },
  "mode": "advanced",
  "labels": "caps",
  "component_options": {
    "image": { "aspect": "4:3", "fit": null, "corners": "rounded", "backdrop": null }
  },
  "top_bar": {
    "layout": "solid", "logo_size": null,
    "show": { "logo": null, "qr": false, "language": null, "audience": null, "identity": null }
  },
  "masthead": {
    "title_size": null, "figures": "tiles",
    "image_side": null, "image_size": null, "image_frame": "inset", "image_corners": null,
    "image_fit": null, "image_focus": null, "image_backdrop": null,
    "show": { "logo": null, "ids": null, "status": null, "figures": null, "image": null, "explore": null }
  },
  "chapters": {
    "header": "numeral", "size": null, "index": null, "tabs": null,
    "show": { "number": null, "icon": false, "divider": null }
  },
  "sections": { "header": null, "size": null, "gallery_columns": "2", "show": { "description": null } },
  "fields": { "rows": null, "dividers": null, "density": null },
  "figures": { "look": null, "size": null, "unit": null, "corners": null },
  "charts": { "colors": null, "grid": null, "legend": null, "bars": "square" },
  "rhythm": { "spacing": null, "width": null }
}

Error

{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_invalid",
    "message": "Pick one of: plain, captioned, framed, file.",
    "param": "components.image",
    "errors": {
      "components.image": ["Pick one of: plain, captioned, framed, file."]
    }
  }
}

That body named four settings, applied to the design from Retrieve the design. The other twenty-two kept whatever they held. colors lists all six roles, with muted, rule and surface null (derived when the passport is drawn). components and charts were replaced: image and file were set before and are null now, and bars is the only chart leaf left.

Events

A successful PATCH emits design.updated. Its payload is byte-identical to the response you just received, so a consumer on the change feed sees the same theme the caller does, with no follow-up read.

There is no design.created. The singleton always exists, so there is no moment of creation to report.

Was this page helpful?