---
title: 'REST API: Preview'
path: reference/rest-api/preview
status: published
---

# REST API: Preview

Live compile + validate endpoints. Both stateless — no persistence, no deploy.

Used by the canvas's right-sidebar Live Preview pane and the inline validation badges. Routes registered before the `/v1/flows/{flow_id}` wildcard so they win.

Both endpoints require `scaicore:view`.

## `POST /v1/flows/compile`

Compile the posted flow JSON to YAML, IR, or `.scai` text. No persistence — the flow doesn't have to be saved.

**Body:**

```jsonc
{
  "content": { /* full FlowGraph JSON */ },
  "format": "yaml"          // or "ir", "scai"
}
```

**Response:**

```jsonc
{
  "format": "yaml",
  "body": "core:\n  name: my-flow\n  ...",   // string body for yaml/scai
  "errors": []                               // compile errors, if any
}
```

For `format: "ir"`, the `body` is base64-encoded MessagePack bytes.

Compile errors come back inside `errors[]` rather than as a 4xx — the canvas's live preview pane renders them inline so the user sees what's wrong as they type. Empty `errors` means clean compile.

## `POST /v1/flows/validate`

Run schema validation + the analyze stage (port wiring, entry detection, cycle detection). Doesn't compile.

**Body:** same as `compile` (just the `content`).

**Response:**

```jsonc
{
  "valid": false,
  "diagnostics": [
    { "severity": "error",
      "message": "edge 'edge_xyz': source node 'node_abc' has no output port 'out_typo'",
      "path": "edges[2]",
      "node_id": null,
      "edge_id": "edge_xyz" },
    { "severity": "warning",
      "message": "node 'node_review' has an unused output port 'out_aux'",
      "node_id": "node_review",
      "edge_id": null }
  ]
}
```

Severity is `error` or `warning`. Errors block compile/deploy; warnings don't.

The canvas indexes diagnostics by `node_id` / `edge_id` / unattached so:

- `<NodeView>` can paint cards red (error) or amber (warning) on the canvas.
- `<PropertyPanel>` can list per-node messages on the selected node.

## Skipped in dev-token mode

Both endpoints require `scaicore:view`. The canvas skips them entirely when `authStore.authMode() !== "scaikey"` to avoid spamming 401 toasts in dev-token mode.

## Debounce

The canvas's `previewStore` debounces calls by 500 ms and uses a monotonic `nextRequest` counter to drop out-of-order responses (so a slow compile from an earlier flow state doesn't overwrite a fast compile from the current state).
