---
title: "Validate a workflow graph without saving it"
method: POST
path: "/v1/workflows/revisions/{revision_id}/graph/validate"
tags: ["workflows"]
---

# Validate a workflow graph without saving it

`POST /v1/workflows/revisions/{revision_id}/graph/validate`

Dry-run validation. ``?gate=draft_save`` answers "would this save as a
draft?" (completeness findings reported but non-blocking); the default
``activate`` answers "would this activate?" — the same split the MCP
``validate_workflow_graph`` tool exposes.

## Path parameters

- `revision_id` string, uuid, required

## Query parameters

- `gate` 'draft_save' | 'activate'

## Request body

- WorkflowGraphRequest — Body for validating or manually replacing a revision's compiled graph.
  - `compiled_graph` object, required
  - `base_version` integer, nullable

## Response `200`

Successful Response

- WorkflowGraphValidationResponse — Validation result for a submitted ``CompiledWorkflowGraph`` payload.
  - `valid` boolean, required
  - `error_count` integer, required
  - `warning_count` integer, required
  - `suggestion_count` integer, required
  - `findings` ValidationFinding[]
    - `severity` 'error' | 'warning' | 'suggestion', required
    - `rule_id` string, required
    - `category` string, required
    - `message` string, required
    - `node_id` string, nullable
    - `edge_id` string, nullable
    - `related_node_ids` string[]
    - `related_edge_ids` string[]
    - `source_span` SourceSpan — Byte/character span into the original instruction markdown. ``start_line``/``end_line`` are 1-indexed; columns are 0-indexed. The optional ``raw_text_excerpt`` carries a small slice for human-readable error messages without forcing readers to re-open the source.
      - `start_line` integer, required
      - `start_col` integer, required
      - `end_line` integer, required
      - `end_col` integer, required
      - `raw_text_excerpt` string, nullable
    - `suggested_fix` string, nullable
    - `related_spans` SourceSpan[]
      - `start_line` integer, required
      - `start_col` integer, required
      - `end_line` integer, required
      - `end_col` integer, required
      - `raw_text_excerpt` string, nullable
  - `normalized_graph` object, nullable
  - `blocking_error_count` integer, nullable

## Other responses

- `400` — Bad request
- `401` — Authentication required
- `404` — Resource not found
- `422` — Validation Error

## Changes

- **2026-08-12** `5a5597ebb2d6` — 9 info
  - added the new optional `query` request parameter `gate`
  - added the new optional request property `base_version`
  - added the optional property `blocking_error_count` to the response with the `200` status
  - added the optional property `retry_after` to the response with the `400` status
  - …5 more

[Change history](https://skmtc.dev/oneloop-hq/apis/feather-api/changes/v1/workflows/revisions/:revision_id/graph/validate/post.md)

---

[API](https://skmtc.dev/oneloop-hq/apis/feather-api.md) · [All operations](https://skmtc.dev/oneloop-hq/apis/feather-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/oneloop-hq/feather-api/revisions/9cd7291d4228/schema)
