# REST API

Divine exposes a REST surface under `/wp-json/divine/v1/` that powers the admin workspace and gives integrations a stable, versioned way to manage apps and worktrees, browse and edit theme code, read git history, persist workspace state, export standalone themes, and render capturable previews. It is the same surface the canvas, browser, code, review, history, and export views call.

```text
/wp-json/divine/v1/
```

Authenticate browser requests from the admin with the standard WordPress REST nonce, and authenticate remote requests with WordPress authentication, typically an Application Password tied to a real user that holds the Divine management capability.

## Permissions

Authorization follows WordPress identity through one management capability that the active workspace backend selects. On a single-site install that capability is `manage_options`; on a multisite install Divine runs from network admin and the capability is `manage_network`. Every route below is gated by that capability at the route boundary. The one exception is the show render routes, which also accept a valid signed preview token so a shared render URL can be opened without an admin session.

| Route group | Permission |
| --- | --- |
| Apps | Divine management capability (`manage_options` / `manage_network`) |
| Worktrees | Divine management capability |
| Builder / Canvas | Divine management capability |
| Code | Divine management capability |
| Git history | Divine management capability |
| Browser state | Divine management capability; state is scoped to the current user |
| Export | Divine management capability |
| Show | Divine management capability, or a valid signed show token for the target |

## Apps

The apps routes list the registered Divine apps the workspace can open and create a new app by cloning an existing one. On a single-site install an app is the active WordPress theme; on multisite an app is a network site with its active theme.

```http
GET  /wp-json/divine/v1/apps
POST /wp-json/divine/v1/apps
```

A `GET` returns each app with its label, stylesheet, logo, and site and admin URLs. A `POST` creates an app by cloning another; send the new `name` and `slug` and the `clone_from` app to copy.

## Worktrees

The worktree routes manage the git-backed theme copies an app is edited through. A worktree lives under `wp-content/themes/<worktree-id>`, and these routes list and create them, read and write individual worktree files, deploy a worktree's files into the app theme, and destroy a worktree without deploying it.

You list and create worktrees per app.

```http
GET  /wp-json/divine/v1/apps/{app_slug}/worktrees
POST /wp-json/divine/v1/apps/{app_slug}/worktrees
```

A single worktree is destroyed by ID. Destroy removes the worktree theme directory and its registry record without promoting any work.

```http
DELETE /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}
```

Deploy promotes the worktree's files into the paired app theme. On multisite it targets the selected site's active theme only, and it never copies database state. The body may carry a deploy `label`, `notes`, and the `resolved_files` selection.

```http
POST /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/deploy
```

The worktree file routes back the review surface. The diff route returns a unified diff for one changed file named by the `path` query parameter, and the file route reads the current and base contents of one file or writes a resolved file back into the worktree workspace.

```http
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/file-diff?path={path}
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/file?path={path}
PUT /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/file
```

A `PUT` sends the file `path`, its `contents`, and an optional `delete` flag to remove the file rather than write it.

```json
{
  "path": "pages/home/index.php",
  "contents": "<?php // resolved file body",
  "delete": false
}
```

## Builder

The builder routes return the static canvas snapshots the workspace renders, for both a main app environment and one worktree environment. The pages route returns the Blockstudio page and block snapshots, the manifest route returns lightweight page and block modification times so the client can detect what changed cheaply, and the item route returns one page or block snapshot named by its `source` and `id` query parameters.

```http
GET /wp-json/divine/v1/apps/{app_slug}/builder/pages
GET /wp-json/divine/v1/apps/{app_slug}/builder/pages/manifest
GET /wp-json/divine/v1/apps/{app_slug}/builder/pages/item
```

The same three snapshots exist for a worktree environment under its worktree ID.

```http
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/builder/pages
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/builder/pages/manifest
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/builder/pages/item
```

## Code

The code routes back the code browser. The tree route returns the browsable file tree for an app, and the file route returns one file's contents named by its `path` query parameter. Worktree file writes go through the worktree code file route, which reads the same way and writes on `PUT`.

```http
GET /wp-json/divine/v1/apps/{app_slug}/code/tree
GET /wp-json/divine/v1/apps/{app_slug}/code/file?path={path}
```

The worktree variants browse and edit a worktree's files.

```http
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/code/tree
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/code/file?path={path}
PUT /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/code/file
```

A `PUT` sends the file `path` and its `contents`.

```json
{
  "path": "blocks/hero/index.php",
  "contents": "<?php // block body"
}
```

## Git History

The git-history routes back the history view for both apps and worktrees. The list route returns the recent commits, accepting an optional `limit` query parameter and an optional `worktree_id` to scope history to a worktree. The commit route returns the detail for one commit by its hash, and the file route returns one file's content at that commit, named by the `path` query parameter. Both detail routes accept an optional `parent` to diff against.

```http
GET /wp-json/divine/v1/apps/{app_slug}/git-history
GET /wp-json/divine/v1/apps/{app_slug}/git-history/{commit}
GET /wp-json/divine/v1/apps/{app_slug}/git-history/{commit}/file?path={path}
```

The `{commit}` segment is a hexadecimal commit hash between 7 and 64 characters.

## Browser State

The browser-state routes persist the admin browser tabs for the current WordPress user. The collection route reads the full state map for the user or clears it, and the scoped route writes one workspace scope's panel state. State is stored in the user's meta, so one reviewer's tabs do not affect another's.

```http
GET    /wp-json/divine/v1/browser-state
DELETE /wp-json/divine/v1/browser-state
PUT    /wp-json/divine/v1/browser-state/{scope_key}
```

A `PUT` sends the panel state for that `scope_key`, and the response returns the full updated state map.

## Export

The export routes build the standalone, client-ready theme zip. Export bundles a copy of the Divine runtime into the theme so the exported theme runs on a site with no Divine plugin installed, and writes provenance and third-party license files alongside it. You export either an app's current theme or a specific worktree.

```http
POST /wp-json/divine/v1/apps/{app_slug}/export
POST /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/export
```

A successful export returns `201` with the exported `theme_slug`, the zip `filename`, a `download_url`, the `size` in bytes, and the `sha256` of the archive.

## Show

The show routes return capturable render documents for a page or block, and a labeled side-by-side compare document. They are the REST side of the `dv show` CLI: the CLI prints a URL, and the agent or browser tool that opens it captures the result. These routes are the one place the management capability is not required on its own. A request is allowed when the current user can manage Divine, or when it carries a valid signed show token for the target, which is what lets a shared render URL be opened without an admin session. The token is passed as a query parameter, and an invalid or missing token on a non-admin request returns `403`.

The page and block render routes exist for both a main app environment and a worktree environment. They return an isolated HTML document with a `text/html` content type. The page route also accepts `mode=live`, which redirects to a signed preview URL of the real page instead of the virtual render; blocks render only as the virtual document.

```http
GET /wp-json/divine/v1/apps/{app_slug}/show/page/{id}
GET /wp-json/divine/v1/apps/{app_slug}/show/block/{id}
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/show/page/{id}
GET /wp-json/divine/v1/apps/{app_slug}/worktrees/{worktree_id}/show/block/{id}
```

The compare route renders several targets together as one labeled document. The targets, their tokens, and their labels are carried in the encoded targets query parameter, and an optional width sizes the document.

```http
GET /wp-json/divine/v1/show/compare
```

## Error Responses

Divine REST handlers return JSON error bodies with a `code` and a `message` and an appropriate HTTP status, so you can handle them with the same conventions as the rest of the WordPress REST API. Validation failures return `400` with a route-specific code such as `divine_invalid_worktree`, `divine_invalid_worktree_file`, `divine_invalid_code_workspace`, `divine_invalid_git_history`, or `divine_invalid_show_target`; a forbidden show request returns `403` with `divine_forbidden`; and an unexpected export failure returns `500` with `divine_theme_export_failed`.
</content>
