# API available to generated pages

The demo app exposes a small per-user workspace API. Every response is JSON and every route is scoped to the signed-in user, so there is no user id in any path. Call it with `uxmorph.api(path, init)`, which prefixes the base URL and attaches the bearer token.

Base URL: `/api`

## GET /tasks

List the user's tasks, newest first.

**Response** — { tasks: Task[] } where Task is { id, title, done, priority: 'low'|'medium'|'high', createdAt, dueAt }

Requires the uxmorph bearer token.

## POST /tasks

Create a task.

**Request** — { title: string, priority?: 'low'|'medium'|'high', dueAt?: string | null }

**Response** — { task: Task }

Requires the uxmorph bearer token.

## PATCH /tasks/{id}

Update a task. Send only the fields you are changing.

**Request** — { title?, done?, priority?, dueAt? }

**Response** — { task: Task }

Requires the uxmorph bearer token.

## DELETE /tasks/{id}

Delete a task.

**Response** — { deleted: string }

Requires the uxmorph bearer token.

## GET /metrics

Workspace metrics for the dashboard. Derived from task state, so they change as tasks do.

**Response** — { metrics: { id, label, value: number, unit: 'currency'|'count'|'ratio', change: number }[] }. Currency values are integer cents; ratios are 0–1.

Requires the uxmorph bearer token.

## GET /activity

Recent workspace activity.

**Request** — ?limit=<1-100>, default 20

**Response** — { activity: { id, actor, action, target, at }[] }

Requires the uxmorph bearer token.

## GET /profile

The signed-in user's profile.

**Response** — { id, name, email, role }

Requires the uxmorph bearer token.

## Notes

- Errors are `{ error: string }` with a 4xx/5xx status. The site's `@/ui/api` client turns them into an `ApiError`.
- There is no pagination; every collection is small by construction.
- Prefer `@/ui/api` over raw fetch — it is typed, already handles the error shape, and works in both runtimes.