Brand kit
The shape of /v1/sites/:org/public/brand and how to consume it from a static site.
Every 9d9 site has a brand kit: identity, logos, palette, typography, voice, contact info, and address. Customers edit it in the dashboard's Brand page; developers building the site read it from one unauthenticated endpoint and render however they want.
Endpoint
GET https://api.9d9.dev/v1/sites/{org_id}/public/brand
CORS *. Edge-cached for 60 seconds with
stale-while-revalidate, so a hot path under load is fast even when the
customer's just saved a change.
Response shape
{
"brand": {
"name": "North Shore Lodge",
"legal_name": "North Shore Lodge LLC",
"tagline": "Lakefront escape on Lake McConaughy",
"description": "A seasonal lakeside resort on Nebraska's largest reservoir.",
"mission": null,
"tone": ["welcoming", "old-school", "honest"],
"do_say": ["lake-fed", "white-sand"],
"dont_say": ["luxury"],
"logos": {
"primary": "https://api.9d9.dev/v1/sites/org_xxx/media/ast_a",
"light": "https://api.9d9.dev/v1/sites/org_xxx/media/ast_b",
"dark": null,
"monochrome": null,
"icon": "https://api.9d9.dev/v1/sites/org_xxx/media/ast_c",
"wordmark": null
},
"favicon": "https://api.9d9.dev/v1/sites/org_xxx/media/ast_d",
"palette": {
"ink": "#0E3A5F",
"cream": "#F8F5EE",
"paper": "#FFFFFF",
"signal": "#E8472C",
"moss": "#3D5240"
},
"palette_css": "--brand-ink:#0E3A5F;--brand-cream:#F8F5EE;--brand-paper:#FFFFFF;--brand-signal:#E8472C;--brand-moss:#3D5240;",
"typography": { "id": "inter-source-serif", "sans": "Inter", "serif": "Source Serif 4" },
"social": {
"facebook": "https://facebook.com/northshorelodge",
"email": "hello@example.com",
"phone": "+1-555-0100"
},
"address": {
"street": "Gate 5 #5 N Shore Rd",
"city": "Lemoyne",
"region": "NE",
"postal_code": "69146",
"country": "US"
}
}
} Logo variants
| Key | When to use |
|---|---|
primary | Default. Use when no special context. |
light | Light-on-dark version. Use over dark hero / footer. |
dark | Dark-on-light version. Use over light backgrounds when primary doesn't fit. |
monochrome | Single-color. Watermarks, OG images, low-color contexts. |
icon | Square symbol mark. Favicons, social avatars, nav badges. |
wordmark | Type-only. Inline body text, plain headers. |
Every variant is optional except primary. Missing variants
return null — write your renderer to fall back to
primary when the context-specific one is absent.
Astro
---
const r = await fetch(`${import.meta.env.PUBLIC_API_URL}/v1/sites/${import.meta.env.ORG_ID}/public/brand`);
const { brand } = await r.json();
const heroLogo = brand.logos.light ?? brand.logos.primary;
---
<style is:global set:html={`:root{${brand.palette_css}}`}></style>
<header style={`background:${brand.palette.ink}`}>
{heroLogo && <img src={heroLogo} alt={brand.name} height="40" />}
</header> Next.js (App Router)
// app/lib/brand.ts
export async function getBrand() {
const r = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/v1/sites/${process.env.ORG_ID}/public/brand`,
{ next: { revalidate: 60 } },
);
return (await r.json()).brand;
} Vanilla
<script>
fetch("https://api.9d9.dev/v1/sites/org_xxx/public/brand")
.then((r) => r.json())
.then(({ brand }) => {
document.documentElement.style.cssText += brand.palette_css;
const logo = document.querySelector("#logo");
if (logo) logo.src = brand.logos.primary;
});
</script> Voice & tone for AI agents
tone, do_say, and dont_say are
written specifically so AI agents drafting copy for the site
can read them. Surface them as a system-prompt snippet when an agent
generates page copy, hero text, or campaign content.
Editing
Brand is updated via the authenticated PATCH /orgs/{org_id}
endpoint with a brand object in the body. The public
endpoint above is for read-only consumption from the static site.