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}.
Endpoints
Read a brand. Send {url, label?, depth?, fresh?, own_ads?}, get {read_id, job_id, status}. MCP tool extract_brand.
The read. MCP tool get_brand_extract.
List reads and raw files. MCP tool get_brand_materials.
Check an output. Send {design_id | asset_id | image_url}, get {score, notes[]}. MCP tool check_against_brand.
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.
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"}'{
"job_id": "job_01J9X4R2M7K3Q8V6N1P5T0W2E",
"read_id": "brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
"url": "https://drinkag1.com",
"depth": "plain",
"status": "reading",
"cached": false
}The document
brandname, 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.
factsproducts[{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.scalesizes[], the heading sizes seen, largest first
identity.componentsbuttons[{name, n, css{default, hover}}], cards[{n, css}]
identity.surfacesgrounds[], 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.
compositionpieces, rules[], devices[], counts{...}, profile{palette[], dark}. Counted from the pieces.
pagesections[{tag, top, h, bg, heading, imgs, buttons}], stylesheets, css_rules
artifactshtml, css[], screenshot. The kept page, as links.
metaread_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.
computedMeasured in a browser from computed styles and painted area
0.9siteStated by the site in its catalogue or structured data
0.9cssFound in the stylesheets (a colour used often, a hover rule)
0.8pixelsMeasured from pictures
0.7ad_library, instagramThe brand's own pieces, as published
0.9modelA model's reading of the page text or the pieces
0.6inferredA rule of thumb where nothing was measured
0.4Using 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
import os, requests
read = requests.get(
"https://api.klayson.com/v1/extract/brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
headers={"Authorization": f"Bearer {os.environ['KLAYSON_API_KEY']}"},
).json(){
"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 }
]
}
}