# 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

| Call | What it does | Cost |
|---|---|---|
| `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.

```sh
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"}'
```

```python
import os, requests

res = requests.post(
    "https://api.klayson.com/v1/extract",
    headers={"Authorization": f"Bearer {os.environ['KLAYSON_API_KEY']}"},
    json={"url": "https://drinkag1.com"},
)
read = res.json()
```

```ts
const res = await fetch("https://api.klayson.com/v1/extract", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.KLAYSON_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://drinkag1.com" }),
});
const read = await res.json();
```

Response, 202:

```json
{
  "job_id": "job_01J9X4R2M7K3Q8V6N1P5T0W2E",
  "read_id": "brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
  "url": "https://drinkag1.com",
  "depth": "plain",
  "status": "reading",
  "cached": false
}
```

## The document

| Key | Holds |
|---|---|
| `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`.

| Source | Meaning | 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

```sh
curl https://api.klayson.com/v1/extract/brd_01J9X4R2M7K3Q8V6N1P5T0W2E \
  -H "Authorization: Bearer $KLAYSON_API_KEY"
```

```python
import os, requests

read = requests.get(
    "https://api.klayson.com/v1/extract/brd_01J9X4R2M7K3Q8V6N1P5T0W2E",
    headers={"Authorization": f"Bearer {os.environ['KLAYSON_API_KEY']}"},
).json()
```

```ts
const res = await fetch("https://api.klayson.com/v1/extract/brd_01J9X4R2M7K3Q8V6N1P5T0W2E", {
  headers: { Authorization: `Bearer ${process.env.KLAYSON_API_KEY}` },
});
const read = await res.json();
```

Response, 200:

```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 }
    ]
  }
}
```
