API Reference
REST API and WebSocket protocol reference for the Design Bridge server.
The bridge server exposes a REST API for session management and a WebSocket endpoint for real-time Yjs CRDT sync. Default base URL: http://localhost:4321.
Endpoints Overview
| Method | Path | Description |
|---|---|---|
GET | /health | Health check |
POST | /api/sessions | Create a session |
GET | /api/sessions | List all sessions |
GET | /api/sessions/:id | Get session metadata |
GET | /api/sessions/:id/state | Get full session state |
POST | /api/sessions/:id/ops | Apply spec operations |
POST | /api/sessions/:id/presence | Update agent presence |
DELETE | /api/sessions/:id | Delete a session |
WS | /ws | Yjs WebSocket sync |
All JSON endpoints return Content-Type: application/json and include CORS headers (Access-Control-Allow-Origin: *).
GET /health
Health check to verify the server is running.
Response:
{ "ok": true }curl:
curl http://localhost:4321/healthPOST /api/sessions
Create a new design session. Initializes a Yjs document with the provided spec and theme.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Session name (default: "Untitled") |
description | string | No | Human-readable description |
spec | Spec | No | Initial Compose spec |
theme | ThemeParams | No | Initial theme parameters |
Response (201):
{
"ok": true,
"session": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Login Page",
"description": "A login form",
"revision": 0,
"createdAt": "2026-03-25T10:00:00.000Z",
"updatedAt": "2026-03-25T10:00:00.000Z"
}
}curl:
curl -X POST http://localhost:4321/api/sessions \
-H "Content-Type: application/json" \
-d '{
"name": "Login Page",
"description": "A login form with email and password",
"spec": {
"root": "container",
"elements": {
"container": {
"type": "Card",
"props": { "className": "p-6" },
"children": ["heading"]
},
"heading": {
"type": "Heading",
"props": { "level": 2, "children": "Login" }
}
}
}
}'GET /api/sessions
List all active sessions.
Response (200):
{
"ok": true,
"sessions": [
{
"id": "a1b2c3d4-...",
"name": "Login Page",
"description": "A login form",
"revision": 5,
"createdAt": "2026-03-25T10:00:00.000Z",
"updatedAt": "2026-03-25T10:05:00.000Z"
}
]
}curl:
curl http://localhost:4321/api/sessionsGET /api/sessions/:id
Get metadata for a single session.
Response (200):
{
"ok": true,
"session": {
"id": "a1b2c3d4-...",
"name": "Login Page",
"description": "A login form",
"revision": 5,
"createdAt": "2026-03-25T10:00:00.000Z",
"updatedAt": "2026-03-25T10:05:00.000Z"
}
}Response (404):
{ "error": "Session not found" }curl:
curl http://localhost:4321/api/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890GET /api/sessions/:id/state
Get the full session state including spec, theme, theme CSS, and metadata.
Response (200):
{
"ok": true,
"spec": {
"root": "container",
"elements": {
"container": {
"type": "Card",
"props": { "className": "p-6" },
"children": ["heading", "form"]
}
}
},
"theme": {
"hue": 264,
"chroma": 0.24,
"grayChroma": 0.01,
"radius": 0.625
},
"themeCSS": ":root { --primary: 39.11% 0.084 264; ... }",
"meta": {
"id": "a1b2c3d4-...",
"name": "Login Page",
"description": "A login form",
"revision": 5,
"createdAt": "2026-03-25T10:00:00.000Z",
"updatedAt": "2026-03-25T10:05:00.000Z"
}
}curl:
curl http://localhost:4321/api/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/statePOST /api/sessions/:id/ops
Apply spec operations to a session. Operations are applied to the Yjs document and synced to all connected browsers immediately.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
ops | SpecOp[] | Yes | Array of spec operations |
agentId | string | No | Agent identifier for audit |
SpecOp Types
type SpecOp =
| { op: "add_element"; key: string; element: UIElement; parentKey: string; index?: number }
| { op: "remove_element"; key: string }
| { op: "update_props"; key: string; props: Record<string, unknown> }
| { op: "set_prop"; key: string; prop: string; value: unknown }
| { op: "remove_prop"; key: string; prop: string }
| { op: "reorder_children"; key: string; children: string[] }
| { op: "set_root"; root: string }
| { op: "replace_spec"; spec: Spec }
| { op: "set_theme"; theme: Partial<ThemeParams> }
| { op: "set_theme_css"; css: string }Response (200):
{
"ok": true,
"revision": 6,
"applied": 3,
"errors": []
}curl:
curl -X POST http://localhost:4321/api/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/ops \
-H "Content-Type: application/json" \
-d '{
"ops": [
{
"op": "add_element",
"key": "submitBtn",
"parentKey": "form",
"element": {
"type": "Button",
"props": { "children": "Submit", "className": "w-full" }
}
},
{
"op": "set_prop",
"key": "heading",
"prop": "children",
"value": "Welcome Back"
}
],
"agentId": "claude"
}'POST /api/sessions/:id/presence
Update agent presence for a session. Presence is stored in memory and visible to connected browsers.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
agentId | string | Yes | Unique agent identifier |
name | string | No | Display name |
cursor | object | No | { elementKey: string } — cursor target |
status | string | No | Agent status (e.g. "working", "idle") |
Response (200):
{
"ok": true,
"presence": {
"claude": {
"agentId": "claude",
"status": "working",
"updatedAt": "2026-03-25T10:05:00.000Z"
}
}
}curl:
curl -X POST http://localhost:4321/api/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/presence \
-H "Content-Type: application/json" \
-d '{
"agentId": "claude",
"status": "working",
"name": "Claude"
}'DELETE /api/sessions/:id
Delete a session and its persisted Yjs document. Clears presence data.
Response (200):
{ "ok": true }Response (404):
{ "error": "Session not found" }curl:
curl -X DELETE http://localhost:4321/api/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890WebSocket: /ws
The /ws endpoint accepts WebSocket connections for Yjs CRDT sync via the Hocuspocus protocol.
Connection
Connect with a Yjs-compatible WebSocket provider. The session ID is the Hocuspocus document name:
import { HocuspocusProvider } from "@hocuspocus/provider";
import * as Y from "yjs";
const doc = new Y.Doc();
const provider = new HocuspocusProvider({
url: "ws://localhost:4321/ws",
name: sessionId, // the session ID is the document name
document: doc,
});Document Structure
The Yjs document contains these top-level maps:
| Map | Type | Description |
|---|---|---|
spec | Y.Map | Compose spec with nested elements |
theme | Y.Map | Theme parameters |
themeCSS | Y.Text | Generated CSS token string |
meta | Y.Map | Session metadata (id, name, revision) |
Reading the Spec
const specMap = doc.getMap("spec");
const root = specMap.get("root") as string;
const elements = specMap.get("elements") as Y.Map<Y.Map<unknown>>;
// Observe changes
specMap.observeDeep((events) => {
// Re-render when spec changes
const spec = yDocToSpec(doc);
renderPreview(spec);
});Awareness Protocol
Presence and cursors use the Yjs Awareness protocol, carried over the same WebSocket connection:
provider.awareness.setLocalState({
agentId: "claude",
status: "working",
color: "#7c3aed",
});
provider.awareness.on("change", () => {
const states = provider.awareness.getStates();
// Render presence indicators
});Type Reference
Spec
interface Spec {
root: string;
elements: Record<string, UIElement>;
state?: Record<string, unknown>;
}UIElement
interface UIElement {
type: string;
props: Record<string, unknown>;
children?: string[];
}ThemeParams
interface ThemeParams {
hue: number; // 0-360
chroma: number; // 0-0.4
grayChroma: number; // 0-0.03
radius: number; // px
font?: string;
}SessionMeta
interface SessionMeta {
id: string;
name: string;
description: string;
revision: number;
createdAt: string; // ISO 8601
updatedAt: string; // ISO 8601
}