Brand Extract API

The brand layer for agents. One call reads what a site serves and keeps it: its font files, its stylesheets and rendered page, every colour with its role and share, the main button and the cards as CSS, the logos, the largest pictures, a screenshot. A second call checks anything an agent made against the brand's own pieces. The ad studio at klayson.com is built on these two calls.

Base URL and auth

Base URL https://api.klayson.com. Send Authorization: Bearer <key> with a key from Settings, API keys, or use the MCP server at /mcp with the same tools. Every long call returns a job; poll GET /v1/jobs/{id}.

dov_live_••••••••3f2a

Endpoints

POST/v1/extract

Read a brand. Send {url, label?, depth?, fresh?, own_ads?}, get {read_id, job_id, status}. MCP tool extract_brand.

1 read
GET/v1/extract/{read_id}

The read. MCP tool get_brand_extract.

Free
GET/v1/brand/materials?read_id=

List reads and raw files. MCP tool get_brand_materials.

Free
POST/v1/check

Check an output. Send {design_id | asset_id | image_url}, get {score, notes[]}. MCP tool check_against_brand.

Free

A plain read takes under a minute: a browser opens the page once, then every stylesheet, font file, logo and picture it lists. depth: full also reads the brand's words, products and design system. The call answers read_id at once; GET /v1/extract/{read_id} is the document below, as far as it has landed.

REQUEST
curl -X POST https://api.klayson.com/v1/extract \
  -H "Authorization: Bearer $KLAYSON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://drinkag1.com"}'
RESPONSE · 202
{
  "job_id": "job_01J9X4R2M7K3Q8V6N1P5T0W2E",
  "read_id": "brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
  "url": "https://drinkag1.com",
  "depth": "plain",
  "status": "reading",
  "cached": false
}

The document

brand

name, url, industry, tagline, what_it_is, audience, voice, tone_examples[], style_classification[]. From a model, with depth full or on the workspace's own site.

facts

products[{name, price, description, cutout}], offers[], claims[], proof_points[], prices, shipping, competitors[], confirmed_by_person

identity.colors[]

hex, role (ground | accent | ink | link | palette), usage[], share (of the painted page)

identity.type[]

role (display | body | label | display_alt), family, fallback_css, served, files[{url, format, weight, style, origin_url}], licensing, specs{size, weight, tt, ls, lh}

identity.scale

sizes[], the heading sizes seen, largest first

identity.components

buttons[{name, n, css{default, hover}}], cards[{n, css}]

identity.surfaces

grounds[], gradients[{css, n}], shadows[{css, n}]

identity.logos[]

url, origin_url, role, format (svg | img | icon | og | ld), w, h, where

identity.media[]

url, origin_url, usage, w, h

materials[]

url, source, tag, caption. The brand's own running ads and posts, with depth full or on the workspace's own site.

composition

pieces, rules[], devices[], counts{...}, profile{palette[], dark}. Counted from the pieces.

page

sections[{tag, top, h, bg, heading, imgs, buttons}], stylesheets, css_rules

artifacts

html, css[], screenshot. The kept page, as links.

meta

read_id, kind, url, final_url, reads, seconds, read_at, sources_opened, own_brand

Links are signed and expire in seven days; fetch the document again for fresh ones.

Source and confidence

Every object carries source and confidence.

computed

Measured in a browser from computed styles and painted area

0.9
site

Stated by the site in its catalogue or structured data

0.9
css

Found in the stylesheets (a colour used often, a hover rule)

0.8
pixels

Measured from pictures

0.7
ad_library, instagram

The brand's own pieces, as published

0.9
model

A model's reading of the page text or the pieces

0.6
inferred

A rule of thumb where nothing was measured

0.4

Using it from an agent

1. extract_brand once per brand; keep read_id.

2. Set type in identity.type[].family; load files[].url with @font-face when served is true, else the closest face of the same kind and weight, never a default sans. The ground is the first colour with role ground, exact. Draw the main button with components.buttons[0].css.default.

3. Look at four to six of materials before drawing; follow composition.rules.

4. check_against_brand on every output; act on the notes, worst first, before showing it.

What we read, and what we never do

Any public website, yours or another brand's. No login walls, no paywalled pages, nothing behind a sign-in.

Font files only when the site serves them itself; each file carries a licensing note: self_hosted, google_fonts, adobe_fonts_domain_locked or third_party_host. A face the site names but does not serve comes back with served: false and no file.

Files are kept in private storage and handed out as signed links that expire in seven days.

A plain read is one page load plus the files the page lists, with a plain user agent. A full read also fetches a few of the site's own pages and its public product feed. Nothing is charged for a read that fails.

Example: the read of drinkag1.com

REQUEST
import os, requests

read = requests.get(
    "https://api.klayson.com/v1/extract/brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
    headers={"Authorization": f"Bearer {os.environ['KLAYSON_API_KEY']}"},
).json()
RESPONSE · 200
{
  "read_id": "brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
  "status": "complete",
  "identity": {
    "colors": [
      { "hex": "#082828", "role": "ground",
        "source": "computed", "confidence": 0.9 },
      { "hex": "#46DE46", "role": "accent",
        "source": "computed", "confidence": 0.9 }
    ],
    "type": [
      { "role": "display", "family": "Newsreader",
        "source": "computed", "confidence": 0.9 },
      { "role": "body", "family": "Inter",
        "source": "computed", "confidence": 0.9 }
    ]
  }
}