API Documentation
BrandAPI turns your design system into a single API endpoint. Call it from any app — your AI tools, design pipeline, or component library always get the latest brand tokens.
Quick Start
Three steps to your first API call.
Create a brand
Sign up at brandapi-ogk6.polsia.app/signup and complete the brand wizard. Define your colors, typography, spacing, voice, and custom tokens.
Get your API key
From the dashboard, open your brand → API Keys tab → Generate key. Your key starts with ba_ and is shown once — copy it now. Requires a Pro plan.
Call the endpoint
Make a single GET request to /v1/brand/context with your API key as the bearer token. You'll get back your full brand context as structured JSON.
# Your first BrandAPI call curl https://brandapi-ogk6.polsia.app/v1/brand/context \ -H "Authorization: Bearer ba_your_api_key_here"
Authentication
All requests to /v1/brand/context require an API key. Two header formats are accepted — use whichever fits your HTTP client.
Authorization: Bearer
Standard Bearer token format. Recommended for most HTTP clients.
Authorization: Bearer ba_your_api_key
X-API-Key
Alternative header for clients that don't support Authorization headers.
X-API-Key: ba_your_api_key
GET /v1/brand/context
Returns the full brand context as structured JSON, optimized for LLM consumption and developer tooling. Only non-empty token sections are included in the response.
Request Headers
| Header | Type | Description |
|---|---|---|
| Authorization | string | Bearer ba_... — API key as bearer token.REQUIRED* |
| X-API-Key | string | Alternative: pass key directly. One of Authorization or X-API-Key is required.REQUIRED* |
* Either Authorization or X-API-Key must be present.
Cache Behavior
Responses include Cache-Control: public, max-age=300, stale-while-revalidate=60. Tokens are cached for 5 minutes by CDNs. Your brand updates will propagate within that window.
Response Schema
A successful response returns HTTP 200 with a JSON object containing your brand tokens.
{ "brand": "Acme Corp", "version": "1.0", "updated_at": "2025-01-16T12:34:56.000Z", "tagline": "Build faster, ship better", "tokens": { "colors": { "primary": { "value": "#7c3aed", "usage": "CTAs and primary actions" }, "accent": { "value": "#a78bfa", "usage": "Hover states and highlights" }, "background": { "value": "#0a0a0c" } }, "typography": { "heading": { "family": "Space Grotesk", "weight": "700", "size": "2rem" }, "body": { "family": "Space Grotesk", "weight": "400", "size": "1rem" } }, "spacing": { "base": "4px", "scale": [4, 8, 12, 16, 20, 24, 32] }, "voice": { "tone": "professional yet approachable", "personality": ["clear", "direct", "innovative"], "do": ["Use active voice", "Keep it concise"], "avoid": ["Jargon", "Passive voice"] }, "custom": { "border_radius": "12px", "shadow": "0 4px 24px rgba(0,0,0,0.4)" } }, "instructions": "When generating content or code for Acme Corp, use these design tokens..." }
Top-Level Fields
| Field | Type | Description |
|---|---|---|
| brand | string | Your brand's display name. |
| version | string | API response version. Currently "1.0". |
| updated_at | string (ISO 8601) | When the brand was last updated. |
| tagline | string | Brand tagline, if set.OPTIONAL |
| tokens | object | All design tokens. Only non-empty sections are included. |
| instructions | string | LLM-ready system instruction for applying these tokens. |
tokens.colors
A map of named colors. Each key is a color role (e.g. primary, accent).
| Field | Type | Description |
|---|---|---|
| [name].value | string | Hex color value, e.g. "#7c3aed". |
| [name].usage | string | Human-readable description of where to use this color.OPTIONAL |
tokens.typography
A map of font roles (e.g. heading, body, mono).
| Field | Type | Description |
|---|---|---|
| [role].family | string | Font family name.OPTIONAL |
| [role].weight | string | Font weight, e.g. "700".OPTIONAL |
| [role].size | string | Font size, e.g. "2rem".OPTIONAL |
| [role].line_height | string | Line height ratio.OPTIONAL |
tokens.spacing
| Field | Type | Description |
|---|---|---|
| base | string | Base spacing unit, e.g. "4px". |
| scale | number[] | Spacing scale in pixels, e.g. [4,8,12,16,20,24,32]. |
tokens.voice
| Field | Type | Description |
|---|---|---|
| tone | string | Overall voice tone description.OPTIONAL |
| personality | string[] | List of personality traits.OPTIONAL |
| do | string[] | Writing guidelines — things to do.OPTIONAL |
| avoid | string[] | Writing anti-patterns to avoid.OPTIONAL |
tokens.custom
Freeform key-value pairs for any additional tokens your brand needs — border radii, shadow values, animation speeds, etc.
Code Examples
# Fetch your brand tokens curl https://brandapi-ogk6.polsia.app/v1/brand/context \ -H "Authorization: Bearer ba_your_api_key_here" # Pretty-print with jq curl https://brandapi-ogk6.polsia.app/v1/brand/context \ -H "Authorization: Bearer ba_your_api_key_here" | jq '.' # Extract just the primary color curl https://brandapi-ogk6.polsia.app/v1/brand/context \ -H "Authorization: Bearer ba_your_api_key_here" \ | jq '.tokens.colors.primary.value'
// fetch-brand.js — call from your backend (Node.js) const API_KEY = process.env.BRANDAPI_KEY; async function getBrandTokens() { const res = await fetch( 'https://brandapi-ogk6.polsia.app/v1/brand/context', { headers: { 'Authorization': `Bearer ${API_KEY}` } } ); if (!res.ok) { const err = await res.json(); throw new Error(err.error); } return res.json(); } // Usage const brand = await getBrandTokens(); console.log(brand.tokens.colors.primary.value); // "#7c3aed" console.log(brand.tokens.typography.heading.family); // "Space Grotesk"
# fetch_brand.py import os import requests API_KEY = os.environ["BRANDAPI_KEY"] def get_brand_tokens(): resp = requests.get( "https://brandapi-ogk6.polsia.app/v1/brand/context", headers={"Authorization": f"Bearer {API_KEY}"} ) resp.raise_for_status() return resp.json() # Usage brand = get_brand_tokens() colors = brand["tokens"]["colors"] primary = colors["primary"]["value"] # "#7c3aed" # Pass to an LLM system prompt system_prompt = brand["instructions"] + " " + str(brand["tokens"])
Try It Live
Paste your API key below and hit the endpoint. Response appears inline — no Postman required.
GET /v1/brand/context
LiveIntegration Examples
Practical patterns for consuming brand tokens in your codebase.
// brand-provider.jsx — fetch tokens server-side, pass as context import { createContext, useContext } from 'react'; const BrandContext = createContext(null); export async function loadBrand() { const res = await fetch('/v1/brand/context', { headers: { 'Authorization': `Bearer ${process.env.BRANDAPI_KEY}` }, next: { revalidate: 300 } // Next.js ISR }); return res.json(); } // Use in a component export function Button({ children }) { const brand = useContext(BrandContext); const primary = brand?.tokens?.colors?.primary?.value ?? '#7c3aed'; const font = brand?.tokens?.typography?.body?.family ?? 'sans-serif'; return ( <button style={{ background: primary, fontFamily: font, color: '#fff', padding: '0.6rem 1.25rem', borderRadius: '8px', border: 'none', cursor: 'pointer' }}> {children} </button> ); }
// tailwind.config.js — inject brand tokens at build time const { getBrandTokens } = require('./scripts/brand'); let brand = { tokens: {} }; try { brand = await getBrandTokens(); } catch { /* use defaults */ } const colors = Object.fromEntries( Object.entries(brand.tokens.colors ?? {}) .map(([name, token]) => [name, token.value]) ); const fonts = Object.fromEntries( Object.entries(brand.tokens.typography ?? {}) .map(([role, t]) => [role, [t.family, 'sans-serif']]) ); module.exports = { theme: { extend: { colors, // bg-primary, text-accent, etc. fontFamily: fonts, // font-heading, font-body } } };
// generate-tokens.js — run at build time or in a server endpoint const res = await fetch('https://brandapi-ogk6.polsia.app/v1/brand/context', { headers: { 'Authorization': `Bearer ${process.env.BRANDAPI_KEY}` } }); const brand = await res.json(); const colors = brand.tokens.colors ?? {}; const spacing = brand.tokens.spacing?.scale ?? []; // Build :root { --primary: #...; ... } const colorVars = Object.entries(colors) .map(([name, t]) => ` --color-${name}: ${t.value};`) .join('\n'); const spaceVars = spacing .map((val, i) => ` --space-${i + 1}: ${val}px;`) .join('\n'); const css = `:root {\n${colorVars}\n${spaceVars}\n}`; // Write to tokens.css require('fs').writeFileSync('./src/tokens.css', css); /* Output: tokens.css :root { --color-primary: #7c3aed; --color-accent: #a78bfa; --space-1: 4px; --space-2: 8px; } */
Error Codes
All errors return a JSON body with an error field and an optional hint.
{ "error": "API key required", "hint": "Pass your API key via Authorization: Bearer ba_xxx or X-API-Key: ba_xxx header" }
API key required
No API key was found in the request headers. Add Authorization: Bearer ba_....
Invalid API key
The provided key doesn't match any active key. Check for typos or regenerate from the dashboard.
API key has been revoked
This key was revoked. Generate a new key from the dashboard → API Keys tab.
Brand not found
The brand associated with this API key no longer exists. Check if the brand was deleted.
Rate limit exceeded
Too many requests. Back off and retry. See Rate Limits for details.
Internal server error
Something went wrong on our end. Retry after a brief pause. If it persists, contact support.
Rate Limits & Caching
Response Caching
Every response includes Cache-Control: public, max-age=300, stale-while-revalidate=60. CDNs and HTTP caches will respect this automatically. Your server should also cache the parsed response in memory.
// cache-brand.js — cache for 5 minutes let cache = { data: null, ts: 0 }; const TTL = 5 * 60 * 1000; // 5 min export async function getBrand() { if (cache.data && Date.now() - cache.ts < TTL) return cache.data; const res = await fetch('https://brandapi-ogk6.polsia.app/v1/brand/context', { headers: { 'Authorization': `Bearer ${process.env.BRANDAPI_KEY}` } }); if (!res.ok) throw new Error(`BrandAPI error: ${res.status}`); cache = { data: await res.json(), ts: Date.now() }; return cache.data; }
Rate Limit Guidance
BrandAPI does not enforce strict per-second rate limits, but excessive polling is detected and may result in temporary 429 responses. Follow these guidelines:
| Pattern | Recommendation |
|---|---|
| Server startup | Fetch once, cache in process memory. Re-fetch every 5 min or on 404. |
| Per-request (SSR) | Cache in Redis or memory with 5-minute TTL. |
| CI / build pipeline | One fetch per build is fine. Cache the output artifact. |
| Client-side (browser) | Don't call from the browser — your API key would be exposed. Proxy through your backend. |