# Northlit API reference

Base URL: `https://northlit.ai`

## Authentication

Every endpoint below takes a self-serve API key as a bearer token:

```bash
curl -H "Authorization: Bearer da_your_key_here" \
     https://northlit.ai/api/projects
```

Create a key in **Settings → Access keys**. Keys are shown once and are
scoped to one user — every response is that user's data. An invalid or
revoked key returns **401**; it never silently degrades to public data.

Optional: send `x-project-id: <projectId>` to scope list endpoints to a
single project.

## Conventions

- Responses are JSON. Errors are `{ "error": "..." }` with a 4xx/5xx status.
- `:runId` accepts either a design-run id (`mb_…`) or a workflow run id.
- Endpoints marked **billable** spend account credits.
- Endpoints marked **long-running** can take minutes. Do not block on them —
  start the work, then poll the corresponding GET.

## MCP server (recommended for agents)

Everything below is also available as a Model Context Protocol server —
tools are self-describing, so a connected agent needs none of this document:

```
https://northlit.ai/api/mcp   (MCP Streamable HTTP)
```

Most MCP clients need only that URL: the server supports OAuth 2.1 with
dynamic client registration, so sign-in and approval happen in the browser.
From Claude Code:

```bash
claude mcp add --transport http northlit https://northlit.ai/api/mcp
```

Or install the Claude Code plugin — the server plus `/northlit:*` slash
commands in one step:

```
/plugin marketplace add 3-Elements-Design/northlit-claude-plugin
/plugin install northlit@northlit
```

From Codex (CLI or IDE extension — OAuth via dynamic client registration):

```bash
codex mcp add northlit --url https://northlit.ai/api/mcp
codex mcp login northlit
```

Or the Codex plugin — `northlit-*` skills plus the server, and the only
route that reaches Codex in ChatGPT:

```
codex plugin marketplace add 3-Elements-Design/northlit-codex
```

then `/plugins` → install Northlit.

In Claude (web or desktop): Settings → Connectors → Add custom connector →
paste the URL. Harnesses without OAuth support can send
`Authorization: Bearer <access key>` instead.

MCP tools (**billable** = spends credits):

**Start here**

- `getting_started` — The full guide: core loop, billing contract, tool reference.
- `whoami` — Your identity, plan, credits, admin flag, and default project.

**Workspace**

- `list_projects` — The user's current project (selected in the app), owned projects, and projects shared with them.
- `create_project` — Mint an empty project — somewhere of its own for new work and its brands.
- `list_runs` — Your explorations (mine) and boards shared with you (sharedWithMe), newest first.
- `list_moodboards` — Your moodboards, grouped by project.
- `list_brands` — Your brand libraries — id, name, and where each sits in its brand tree.
- `read_brand` — One brand's full DNA — palette, type, voice, logos.
- `search_brand` — Passages from a brand's stored sources and its ancestors', by meaning and exact words, each with where it came from.
- `set_project_brand` — Add a brand to a project's brands; a project with no brand DNA takes it as its DNA too.
- `remove_project_brand` — Take a brand out of a project's brands; the brand itself is untouched.
- `extract_brand` — Brand DNA from a live website — exact colors, fonts, logo file, screenshots; create: true mints it.
- `create_brand` — Mint a brand in the library from a brand-spec you write — the from-scratch step when there is no site to extract.
- `create_sub_brand` — Add a sub-brand or product under a brand; its spec says only what differs and inherits the rest.
- `make_product_nodes` — Turn the products a brand lists into product nodes under it, each with its own spec and photos.
- `add_brand_artifact` — Add to a brand: a source (capture a page or a PDF, or text; search_brand reads it) or an approved example image its new work takes as a style reference.
- `record_brand_decision` — Record a decision about a brand in its memory: house notes its work reads next to the Spec, not binding.
- `update_brand_spec` — Rewrite one or more sections of a brand's spec, leaving the rest as it was; identity and requirements edits ask a person.
- `list_design_systems` — Saved design systems — conform explorations via systemIds.

**Boards**

- `create_board` — Start a board: open a run as one (idempotent), or start fresh with a blank section.
- `read_board` — What is on the board a run was opened as — its sections and the full text of its notes, with ids and positions.
- `add_note` — Put a markdown note on a board — a brief, a rationale, what to try next. Free.
- `update_note` — Replace a note's markdown, wholesale. Note ids come from read_board.
- `add_reference` — Pin one of our images on a board as a reference to design against.
- `place_nodes` — Arrange a board — move its notes and section frames to canvas coordinates.
- `create_section` — A new, empty section on a board: a blank run of its own. Generate into the run id it returns.

**Brand books**

- `list_brand_books` — Brand books in a project — check here before minting another.
- `read_brand_book` — Which brand-world artifacts a book has, is making, or is missing.
- `share_brand_book` — Mint the PUBLIC view-only /bb/… link for a brand book (bookId or projectId); idempotent.
- `unshare_brand_book` — Disable a brand book's public link (the same link re-enables later).
- `create_brand_book` — Mint a book from a project's brand DNA. Free — no imagery yet.
- `generate_brand_world` — **billable** — Generate a book's imagery — all 11 artifacts or a named subset.

**Explorations & boards**

- `create_exploration` — **billable** — Start a run from a brief — a board of direction mocks; returns openUrl + project.
- `check_progress` — Poll a run's pipeline phase and per-direction milestones.
- `generate_mocks` — **billable** — Generate board image mocks for directions without them.
- `add_directions` — **billable** — More TOP-LEVEL directions on an existing board (no parent card).
- `generate_variations` — **billable** — Child variations OF a card — attached under it, its image as edit base.
- `start_logo_workflow` — **billable** — Kick off a logo set — 1-6 marks from a prompt and/or references, on their own canvas.
- `start_lookbook` — **billable** — Kick off a lookbook — event renders, vignettes, catalog and overhead assets under the project's brand.
- `reparent_card` — Attach an orphan top-level card under another card (childless cards only).
- `list_directions` — Directions in a run with their mocks — renders as an inline gallery in ChatGPT.
- `read_direction` — One direction's full markdown.
- `read_run` — A run's AGENTS.md — the entry point before other reads.
- `read_moodboard` — A run's moodboard as markdown.
- `read_activity` — Reverse-chronological audit log of a run.
- `upscale_image` — **billable** — Upscale a direction's mock to 4K.
- `diff_directions` — Deterministic axis-by-axis diff of two directions.
- `critique_design` — **billable** — Principal-designer critique of a card — 0-100 scores, ranked issues, refine-ready fixPrompt.
- `present_board` — One composed side-by-side grid of a board's direction mocks — the comparison view for decision moments.
- `share_board` — Mint the PUBLIC view-only /b/… link for a run's board; idempotent.
- `unshare_board` — Disable a board's public link (the same link re-enables later).

**Prototypes**

- `build_prototype` — **billable** — Select a direction and build the full HTML prototype.
- `edit_prototype` — **billable** — Natural-language edit that lands as a new saved version.
- `list_prototype_versions` — A prototype's saved version history.
- `revert_prototype` — Make a prior version active (append-only).
- `read_prototype` — A prototype's overview, score, and version history.
- `read_prototype_html` — A prototype's raw rendered HTML.
- `read_chat` — The chat timeline for one direction.
- `publish_prototype` — Deploy a prototype to its public share URL.
- `unpublish_prototype` — Take a published prototype offline.
- `import_prototype` — Bring existing built files in — text in files[], images in assets[] (copied onto the run); a new canvas, or attached with runId + directionId.
- `get_build_link` — Tokenized handoff URL any coding agent can fetch.
- `generate_prototype_image` — **billable** — Generate a hosted raster image INTO an existing prototype.
- `crop_mock_region` — Crop a region out of a direction's source mock (hosted URL).
- `view_mock` — See a direction's source mock — renders inline for the user too.

**Imagery**

- `list_models` — Model catalog — image (flat 1 credit) + priced video models; ids feed generate_image / generate_video.
- `generate_image` — **billable** — ONE image from a prompt — lands on its own editable canvas; optional model pick.
- `upload_reference_image` — Rehost a local image (data URL) to a usable https reference URL.
- `import_image` — Bring an EXISTING image (https or data URL) in — its own canvas, or a new card on an existing board with runId.
- `view_image` — Render any Northlit-hosted image inline in the chat.
- `present_images` — Inline gallery widget of finished images — the display path for ChatGPT.
- `image_to_prompt` — **billable** — Reverse-prompt an image for ui/image/video scopes.

**Social**

- `write_caption` — **billable** — On-brand captions per network (Instagram, Facebook, LinkedIn, TikTok, YouTube, X, Threads), fitted to each limit and judged against the brand's voice and claims.
- `compose_carousel` — **billable** — A planned carousel (hook, body, CTA slides) rendered on-brand on one canvas, with its caption.

**Video & 3D**

- `generate_video` — **billable** — Image-to-video render on the model registry.
- `check_video_status` — Poll a video job; the finished clip is billed on delivery.
- `save_video` — Persist a finished clip to a run — rehosted + indexed.
- `read_timeline` — A video project's timeline (videoDocId) — tracks, clips, ids, times, end marker, its board; no id lists the video projects.
- `edit_timeline` — Queue add/update/remove/move clip edits and the end marker onto a video project (videoDocId; one undo step).
- `list_media` — The person's uploads and generated clips, audio and images (with their canvas; runId filters to one) — URLs for the timeline.
- `video_options` — Video models with their text/image/reference modes, lengths, aspects; lip-sync models; camera moves; voiceover voices.
- `generate_clip` — **billable** — Text, image or references (image/video/audio) to video, or lip sync a face to audio — lands via check_clip.
- `check_clip` — Poll a generate_clip job; on delivery bill, save to the Library, place on the timeline, return a download link.
- `generate_voiceover` — **billable** — Text to speech (ElevenLabs v3) saved to the Library — a speech track for lip sync or the timeline.
- `generate_music` — **billable** — An instrumental cue at a chosen BPM, saved to the Library and placed with its tempo — the editor finds the beat grid for cutting on hits.
- `generate_captions` — Transcribe a video project's speech with word timings and place it as captions on a Captions track (burned into the export; .srt from the Export menu).
- `analyze_video` — **billable** — Break a video down: its shot list (cuts, times, pacing) and a numbered, timed contact sheet.
- `preview_motion` — Stills of a motion-graphics composition you wrote, seeked like the renderer, on a contact sheet — over a backdrop; checks the render contract.
- `render_motion` — **billable** — Render your motion-graphics composition to a clip — opaque mp4, or a transparent webm overlay; lands via check_clip.
- `generate_3d` — **billable** — Turn a direction's mock into a 3D GLB model.
- `create_scene` — Start a three.js scene as a card — empty stage, your module, or an imported GLB — rendered server-side to a contact sheet.
- `read_scene` — A scene's head revision: module source, object graph, assets, revisions, contact sheet.
- `edit_scene` — Commit the next revision of a scene from a resubmitted module; renders a contact sheet; stale revisions are refused.
- `import_scene_asset` — Bring a hosted GLB, texture or HDRI into a scene under a name the module quotes.
- `render_scene` — **billable** — Named views and turntables of a scene revision; finals land as cards.
- `export_scene` — A scene revision as a compressed GLB (lands a 3D model card) or its module source.
- `revert_scene` — Make an earlier scene revision the head again.
- `generate_scene_angles` — **billable** — A finished photographic image from a scene revision's render — the 3D view fixes camera, framing, placement and light; brand, product and model as generate_image.

**Design knowledge**

- `list_skills` — Catalog of design skills (name, description, when to use).
- `get_skill` — Full markdown body of one skill.
- `semantic_search` — Vector search across skills and run artifacts.
- `search_inspiration` — Vibe-search the curated inspiration gallery — free.
- `get_inspiration` — One inspiration item in full — prompt, image, palette; adapt via create_exploration.
- `search_community` — Search published Brand DNA, ads and reels on Northlit Community — free.
- `get_published_dna` — A published brand's palette, type and voice — json, md, DESIGN.md or DTCG tokens, with attribution — free.

**Design systems & exports**

- `read_design_system` — A run's design system as markdown.
- `render_design_md` — Deterministic design.md from a system's spec block or a brand's DNA (brandId).
- `export_dtcg` — Deterministic W3C Design Tokens (DTCG) JSON export.
- `export_react` — **billable** — A built prototype as a React + TypeScript project: one component per section, tokens.css + globals.css, Vite scaffold.

**Pixel-perfect kit**

- `render_html` — Headless Chromium render of HTML to a PNG screenshot.
- `diff_against_mock` — **billable** — Render HTML and score it against a target mock with fixes.
- `ground_truth_hints` — OCR blocks, layers, and regions extracted from a mock.
- `match_html_to_mock` — **billable** — Run the render→diff→fix loop until HTML matches a mock.

**Advanced (stateless)**

- `analyze_moodboard` — **billable** — Stateless/advanced — vision analysis of moodboard images; saved nowhere.
- `generate_directions` — **billable** — Stateless/advanced — direction JSON only; saved nowhere.
- `generate_design_system` — **billable** — Stateless/advanced — design-system JSON from a direction; saved nowhere.

MCP resources: `skill://<name>`, `run://<id>`.

## Account

Who the key acts as, and what it can spend.

### `GET /api/billing/status`

The caller's plan, admin flag, credit pool + usage, and limits — check before billable work.

Returns: `{ enforced, plan, admin, limits, usage, … }`

## Discovery

List what the authenticated user owns. All are scoped to the key's user; pass x-project-id to narrow to one project.

### `GET /api/projects`

Projects owned by or shared with the caller.

Returns: `{ projects: [{ id, name, … }] }`

### `GET /api/runs`

Explorations (runs), newest first.

Returns: `{ runs: [{ id, name, status, thumbnails, … }] }`

### `GET /api/moodboards`

Moodboards, plus boards shared with the caller.

Returns: `{ moodboards: [...], shared: [...] }`

### `GET /api/prototypes`

Built prototypes across runs.

| param | type | notes |
|---|---|---|
| `offset` | number | pagination offset |
| `limit` | number | page size (default 24, max 60) |

Returns: `{ prototypes: [...], total }`

### `GET /api/systems`

Saved design systems.

Returns: `{ systems: [{ id, name, palette, type, … }] }`

### `GET /api/gallery`

Every generated image, grouped by exploration.

Returns: `{ images: [{ url, runId, directionId, palette, … }] }`

### `GET /api/favorites`

Favorited directions and whole-canvas favorites.

Returns: `{ favorites: [...], canvases: [...] }`

## Exploration

Read one run and everything on its canvas.

### `GET /api/run/:runId`

Run metadata — status, brief, directions.

### `GET /api/run/:runId/board`

The canvas: image mocks, directions, prototypes, and their asset URLs.

Returns: `{ imageMocks: [...], directions: [...], … }`

### `GET /api/run/:runId/brand-checks`

The latest brand check of each card (or ?card=<directionId|variationId>), per format (a card's mock and its prototype apart): each check against the brand's Spec (palette share, the logo, a prototype's fonts and legal lines; voice and claims by a copy judge once those pass) passed or failed, with what it measured. Shadow mode: nothing re-renders on a failure yet.

### `GET /api/run/:runId/design-md`

The run's design.md specification.

### `POST /api/run/:runId/reparent`

Attach an orphan top-level card under another card. Body: { directionId, newParentId } — newParentId accepts a direction id or variation id. Childless cards only.

### `GET /api/run/:runId/progress`

Pipeline progress — phase (queued/setup/reading/diverging/ready/failed) plus per-direction mock + build milestones. Poll this instead of blocking on long-running work.

## Prototypes

Read, edit, audit, and publish a built prototype. :directionId identifies which direction within the run.

### `GET /api/run/:runId/prototype/files`

The prototype's source files (HTML/CSS/JS).

### `GET /api/run/:runId/code/:directionId`

Export the prototype as production code.

### `POST /api/run/:runId/prototype/chat` — **billable**, **long-running**

Ask the edit agent to change the prototype in natural language. Each message produces a new saved version.

| param | type | notes |
|---|---|---|
| `message` | string | what to change |

### `POST /api/run/:runId/lighthouse/:directionId` — **long-running**

Run a Lighthouse audit against the prototype's public URL. Requires the prototype to be published.

Returns: `{ published, report: { scores, issues, fixed, … } } — issues carry a lifecycle across scans`

### `GET /api/run/:runId/lighthouse/:directionId`

The stored audit report without re-scanning.

### `POST /api/run/:runId/deploy/:directionId`

Publish (or republish) the prototype to a public share URL.

Returns: `{ published, url, meta }`

### `DELETE /api/run/:runId/deploy/:directionId`

Unpublish. The slug is retired, not reused.

### `POST /api/run/:runId/build-link/:directionId`

Mint the agent handoff link — a tokenized /build/<name>.md any coding agent can fetch to rebuild this design.

Returns: `{ url, token, stem }`

### `GET /api/run/:runId/prototype/history`

Version history for a direction's prototype. Query: ?directionId=X.

### `POST /api/run/:runId/prototype/revert`

Make a prior version active (append-only — nothing is lost). Body: { directionId, version }.

### `POST /api/run/:runId/upscale` — **billable**

Upscale a direction's mock to 4K. Body: { directionId, kind? }. Idempotent — repeats return the stored upscale (cached: true).

### `POST /api/run/:runId/critique` — **billable**

Principal-designer critique of one Northlit-hosted card image. Body: { imageUrl, directionName? }. Returns { critique } — 0-100 scores (overall, hierarchy, typography, color, layout, content), working, severity-ranked issues with fixes, and a refine-ready fixPrompt. Model-graded judgment; nothing is persisted.

## Video

Image-to-video generation on the model registry. Billed by model weight × duration × resolution when the finished clip is delivered.

### `POST /api/video/generate` — **billable**, **long-running**

Kick off an image-to-video job. Body: { imageUrl, prompt, model?, duration?, resolution?, generateAudio? }. Returns { requestId, statusUrl, responseUrl, cancelUrl }.

### `GET /api/video/:requestId/status`

Poll a job with ?statusUrl=&responseUrl= from the submit response until COMPLETED (→ videoUrl) or FAILED.

### `POST /api/run/:runId/video`

Persist a completed clip onto a run as its own canvas card (rehosts the expiring fal URL to durable storage). Body: { directionId, videoUrl, model, prompt?, durationSeconds?, resolution? }.

## Brands

Brand libraries (brand DNA). A locked brand's spec is injected into generation as a hard constraint.

### `GET /api/brands`

Your brand roster — id, name, slug, and its place in the brand graph (parentId, kind).

### `GET /api/brands/:id`

One brand's full DNA — palette, typography, voice, logo assets, strategy. Accepts id or slug. `spec` is the brand's own; a sub-brand, a product or a brand with product nodes also returns `effectiveSpec` (its ancestors' sections laid under its own, its product nodes in its Products section) and per-section provenance. `system` is the design system it generates with when nothing is picked: its own, or inherited (`from` names the ancestor).

### `GET /api/brands/:id/children`

The brand's direct sub-brands and products.

### `POST /api/brands/:id/children`

Add a sub-brand or product under the brand ({ name, kind: "sub_brand" | "product", spec? }). Its spec only needs what differs; the rest is inherited.

### `POST /api/brands/:id/product-nodes`

Turn products listed in the brand's Products section into product nodes under it ({ names? }, omitted = all). Each node takes its line and photos; the brand's effective Spec still lists every product.

### `GET /api/brands/:id/documents`

The brand's stored sources (site pages, site facts, guideline PDFs, pasted copy) and its ancestors', each with its kind, origin and chunk count. What search reads.

### `POST /api/brands/:id/documents`

Store a source for the brand: { data, name } a guideline PDF (≤ 15 MB, read page by page; only its text is kept), or { text, title?, kind? } pasted copy or guideline text. DELETE ?id= removes one of its own.

### `GET /api/brands/:id/examples`

The brand's approved examples and its ancestors' — starred mocks, published prototypes, added images, brand-world finals — each with its format (site | image) and source. New work of that format takes them as style references. POST { url, format } adds one; DELETE ?id= removes one of its own.

### `GET /api/brands/:id/memories`

What the brand has learned from its work and its ancestors': keeps (starred mocks), kills (deleted cards), critiques, decisions, each one sentence with its kind and polarity. POST { text } records a decision; DELETE ?id= removes one of its own.

### `GET /api/brands/:id/proposals`

Proposed edits to the brand's own Spec waiting for review, drafted from its memories and its sub-brands': per section the current and proposed text, each new line with the memories behind it, the sub-brands a promoted line came from, and memories that disagree. POST drafts new ones now (needs 5 open memories; not while some wait).

### `POST /api/brands/:id/proposals/:proposalId`

{ action: "approve" | "reject" }. Approving writes the section into the Spec (a consolidation version) and folds its memories in; a section edited since is stale (409). Rejecting keeps those memories out of later proposals.

### `GET /api/brands/:id/search`

Search the brand's stored sources and its ancestors' (?q=, &k= 1-20): passages found by meaning and by exact words, each with its citation (kind, title, URL, page or section) and the brand that holds it.

### `GET /api/brands/:id/spec-versions`

The brand's Spec history, newest first — version, source, who, when, and the spec.

### `POST /api/brands/:id/spec-versions`

Restore a version ({ version }) as the current Spec; the restore is recorded as a new version.

## Utilities

Prompt tooling around the generators.

### `POST /api/image-to-prompt` — **billable**

Reverse-prompt an image. Body: { image, scope?: "ui" | "image" | "video" }. Returns { prompt }.

### `POST /api/enhance-prompt` — **billable**

Rewrite a short prompt into a specific, model-friendly one. Body: { prompt, scope?, context? }. Returns { enhanced }.

## Generation

Cost-bearing endpoints. These spend the account's credits and can take minutes — start them, then poll rather than blocking.

### `POST /api/run` — **billable**, **long-running**

Start a new exploration from a brief. Body: { brief: { prompt }, imageUrls? (https or data:), directionCount?, styleIds?, mode? ("raw" renders the brief as written, "images" varies the takes, "ui" makes website/app screens; omitted → "ui" when the brief names a screen, else "raw"), convergence? ("match" default | "balanced" | "vary") }. Returns { runId, designRunId } — designRunId (mb_…) is the id every other endpoint takes; poll /api/run/:designRunId/progress. The exploration appears in the app under Explorations.

### `POST /api/run/scratch`

Create a scratch canvas — a real run seeded from one image, existing built files, or blank. Body: { mode: "image", imageUrl, name? }, { mode: "prototype", files: [{ path, contents }], assets?: [{ path, dataUrl }], name? } (index.html required; assets are images, copied onto the run and rewritten in the markup) or { mode: "blank", width?, height? }. Returns { runId, directionId, buildUrl? }; opens on the live canvas at /canvas/:runId.

### `POST /api/run/:runId/attach-image`

Add an arbitrary image to an existing board as a new top-level card. Body: { imageUrl (https or data:), name?, prompt? }. The image is rehosted onto the run's own storage. Returns { directionId, variationId, imageUrl, width, height }; the canvas shows the card on its next poll.

### `POST /api/run/:runId/prototype/save`

Write a prototype onto an EXISTING card. Body: { directionId, files: [{ path, contents }], assets?: [{ path, dataUrl }] } (index.html required — the Upload flow's ingest, appended as a new version; assets are images copied onto the run and rewritten in the markup) or { directionId, html, summary? }. Returns { entry, warnings }. This is how an imported layout joins an imported image on one canvas.

### `POST /api/run/:runId/select` — **billable**, **long-running**

Select a direction and kick off the full prototype build. Body: { directionId }. Poll progress on the same run id.

### `POST /api/run/:runId/more` — **billable**, **long-running**

Add directions to an existing board — same canvas, new diverging cards. Body: { count?, prompt?, extraStyleIds?, extraSystemIds? }. Poll the board until they land.

### `POST /api/run/:runId/refine` — **billable**, **long-running**

Child variations of a card on the same canvas. Body: { parentVariationId, parentDirectionId, refinementPrompt } — multi-ask prompts fan out. Returns { children }.

### `POST /api/run/:runId/generate-3d` — **billable**, **long-running**

Generate a 3D model (GLB) from an image on the canvas.

### `POST /api/run/:runId/mint` — **billable**, **long-running**

Generate image mocks for directions that don't have them yet.

| param | type | notes |
|---|---|---|
| `directionIds` | string[] | which directions |
| `count` | number | how many, when unspecified |

## Agent handoff

`POST /api/run/:runId/build-link/:directionId` returns a tokenized URL:

```
https://northlit.ai/build/<Design_Name>.md?token=…
```

Fetch it to get complete build instructions for a design — the reference
image, the full design system as tokens, the design.md spec, and the
rendered markup. It needs no API key (the token is scoped to that one
design), so it can be handed to any agent or teammate directly.
