> ## Documentation Index
> Fetch the complete documentation index at: https://docs.retab.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Plan Workflow Spec

> Preview the changes a declarative YAML spec would make to the draft workflow.

Compares the spec against the current draft and returns the resulting
changes without applying them. A spec that already matches the draft
plans as a no-op.

Compute the reconcile plan for a declarative workflow YAML spec against the current draft workflow. This does not mutate workflow state.

Use this before `apply()` to see whether the spec will create a workflow, update blocks and edges, or no-op.

<RequestExample>
  ```python Python theme={null}
  from retab import Retab

  client = Retab()

  plan = client.workflows.plan(yaml_definition)

  print(plan.action)
  print(plan.rendered_plan)
  for change in plan.resource_changes:
      print(change.actions, change.target, change.target_id)
  ```

  ```typescript TypeScript theme={null}
  import { Retab } from "@retab/node";

  const client = new Retab({ apiKey: process.env.RETAB_API_KEY });

  const plan = await client.workflows.plan(yamlDefinition);

  console.log(plan.action);
  console.log(plan.renderedPlan);
  for (const change of plan.resourceChanges) {
    console.log(change.actions, change.target, change.targetId);
  }
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"
  	"log"

  	retab "github.com/retab-dev/retab/clients/go"
  )

  func ptr[T any](v T) *T { return &v }

  func main() {
  	ctx := context.Background()

  	client, err := retab.NewClient("")
  	if err != nil {
  		log.Fatal(err)
  	}

  	yamlDefinition := `apiVersion: workflows.retab.com/v1alpha2
  kind: Workflow
  metadata:
    id: wf_invoice_demo
    name: Invoice Workflow
  spec:
    blocks:
      start:
        type: start_json
        label: Input JSON
        config:
          json_schema:
            type: object
            required:
              - value
            properties:
              value:
                type: string
    edges: []
  `
  	plan, err := client.Workflows.Plan(ctx, &retab.WorkflowsPlanParams{
  		YamlDefinition: yamlDefinition,
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	fmt.Println(plan.Action)
  	fmt.Println(plan.RenderedPlan)
  	fmt.Println(plan.ResourceChanges)
  }
  ```

  ```ruby Ruby theme={null}
  require 'retab'

  client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])

  plan = client.workflows.plan(yaml_definition: yaml_definition)

  puts plan.action
  puts plan.rendered_plan
  plan.resource_changes.each do |change|
    puts "#{change.actions} #{change.target} #{change.target_id}"
  end
  ```

  ```rust Rust theme={null}
  use retab::models::DeclarativeWorkflowRequest;
  use retab::resources::workflows::PlanParams;
  use retab::Retab;

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let client = Retab::new(std::env::var("RETAB_API_KEY")?);

      let yaml_definition = r#"apiVersion: workflows.retab.com/v1alpha2
  kind: Workflow
  metadata:
    id: wf_invoice_demo
    name: Invoice Workflow
  spec:
    blocks:
      start:
        type: start_json
        label: Input JSON
        config:
          json_schema:
            type: object
            required:
              - value
            properties:
              value:
                type: string
    edges: []
  "#;
      let plan = client
          .workflows()
          .plan(PlanParams::new(DeclarativeWorkflowRequest::new(
              yaml_definition,
          )))
          .await?;

      println!("{}", plan.action);
      println!("{}", plan.rendered_plan.as_deref().unwrap_or(""));
      for change in plan.resource_changes.unwrap_or_default() {
          println!("{:?} {} {}", change.actions, change.target, change.target_id);
      }
      Ok(())
  }
  ```

  ```php PHP theme={null}
  <?php
  require 'vendor/autoload.php';

  use Retab\Client;

  $client = new Client(apiKey: getenv('RETAB_API_KEY'));

  $yamlDefinition = <<<'YAML'
  apiVersion: workflows.retab.com/v1alpha2
  kind: Workflow
  metadata:
    id: wf_invoice_demo
    name: Invoice Workflow
  spec:
    blocks:
      start:
        type: start_json
        label: Input JSON
        config:
          json_schema:
            type: object
            required:
              - value
            properties:
              value:
                type: string
    edges: []
  YAML;

  $result = $client->workflows()->plan(yamlDefinition: $yamlDefinition);
  print_r($result);
  ```

  ```csharp C# theme={null}
  using Retab;
  using RetabClient = Retab.Retab;

  var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
  var client = new RetabClient(apiKey);

  var yamlDefinition = """
  apiVersion: workflows.retab.com/v1alpha2
  kind: Workflow
  metadata:
    id: wf_invoice_demo
    name: Invoice Workflow
  spec:
    blocks:
      start:
        type: start_json
        label: Input JSON
        config:
          json_schema:
            type: object
            required:
              - value
            properties:
              value:
                type: string
    edges: []
  """;

  var result = await client.Workflows.PlanAsync(
      new WorkflowsPlanOptions { YamlDefinition = yamlDefinition }
  );
  Console.WriteLine(result);
  ```

  ```java Java theme={null}
  import com.retab.RetabClient;

  public final class Example {
    public static void main(String[] args) throws Exception {
      RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));

      var result = client.workflows().plan("metadata:\n  id: invoice-workflow\n", null, null);
      System.out.println(result);
    }
  }
  ```

  ```curl cURL theme={null}
  curl -X 'POST' \
    'https://api.retab.com/v1/workflows/spec/plan' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer <your-api-key>' \
    -d '{
      "yaml_definition": "apiVersion: workflows.retab.com/v1alpha2\nkind: Workflow\nmetadata:\n  id: wf_invoice_demo\n  name: Invoice Workflow\nspec:\n  blocks:\n    start:\n      type: start_json\n      label: Input JSON\n      config:\n        json_schema:\n          type: object\n          required:\n            - value\n          properties:\n            value:\n              type: string\n  edges: []\n"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "workflow_id": "wf_abc123",
    "action": "update",
    "block_count": 2,
    "edge_count": 1,
    "diagnostics": {
      "issues": []
    },
    "format_version": "workflows-plan/v1",
    "summary": {
      "add": 0,
      "change": 1,
      "destroy": 0,
      "replace": 0,
      "noop": 0,
      "total": 1,
      "has_changes": true
    },
    "resource_changes": [
      {
        "address": "workflow.wf_abc123.block.block_extract",
        "target": "block",
        "target_id": "block_extract",
        "name": "Extract Fields",
        "type": "extract",
        "actions": ["update"],
        "summary": "Update block 'Extract Fields'",
        "change": {
          "before": {
            "label": "Extract Fields",
            "config": {
              "model": "gpt-4.1"
            }
          },
          "after": {
            "label": "Extract Fields",
            "config": {
              "model": "gpt-5.1"
            }
          },
          "before_sensitive": {},
          "after_sensitive": {},
          "field_changes": [
            {
              "path": ["config", "model"],
              "path_display": "config.model",
              "action": "update",
              "before": "gpt-4.1",
              "after": "gpt-5.1",
              "before_sensitive": false,
              "after_sensitive": false,
              "unified_diff": null
            }
          ]
        },
        "path": "extract-node"
      }
    ],
    "rendered_plan": "Workflow: wf_abc123\nPlan: 0 to add, 1 to change, 0 to destroy.\n\n~ workflow.wf_abc123.block.block_extract\n  block \"Extract Fields\" will be updated\n  ~ config.model\n    - 'gpt-4.1'\n    + 'gpt-5.1'"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml POST /v1/workflows/spec/plan
openapi: 3.1.0
info:
  title: FastAPI
  version: 0.1.0
servers:
  - url: https://api.retab.com
security: []
paths:
  /v1/workflows/spec/plan:
    post:
      tags:
        - Workflows
      summary: Plan Workflow Spec
      description: >-
        Preview the changes a declarative YAML spec would make to the draft
        workflow.


        Compares the spec against the current draft and returns the resulting

        changes without applying them. A spec that already matches the draft

        plans as a no-op.
      operationId: plan_workflow_spec
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeclarativeWorkflowRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeclarativePlanResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - HTTPBearer: []
components:
  schemas:
    DeclarativeWorkflowRequest:
      properties:
        yaml_definition:
          type: string
          title: Yaml Definition
          description: Workflow YAML definition
        project_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Project Id
          description: >-
            Project that should own a workflow created from this spec. Required
            when applying a spec that creates a new workflow.
      additionalProperties: false
      type: object
      required:
        - yaml_definition
      title: DeclarativeWorkflowRequest
      description: >-
        Body carrying a workflow's full YAML definition for validate, plan,
        apply, or export.
    DeclarativePlanResponse:
      properties:
        workflow_id:
          type: string
          title: Workflow Id
        action:
          type: string
          enum:
            - create
            - update
            - noop
          title: Action
        block_count:
          type: integer
          title: Block Count
        edge_count:
          type: integer
          title: Edge Count
        diagnostics:
          additionalProperties: true
          type: object
          title: Diagnostics
        format_version:
          type: string
          title: Format Version
          default: workflows-plan/v1
        summary:
          $ref: '#/components/schemas/DeclarativePlanSummary'
          default:
            add: 0
            change: 0
            destroy: 0
            replace: 0
            noop: 0
            total: 0
            has_changes: false
        resource_changes:
          items:
            $ref: '#/components/schemas/DeclarativePlanResourceChange'
          type: array
          title: Resource Changes
          default: []
        rendered_plan:
          type: string
          title: Rendered Plan
          default: No changes. Workflow spec is up to date.
      type: object
      required:
        - action
        - block_count
        - diagnostics
        - edge_count
        - workflow_id
      title: DeclarativePlanResponse
      description: >-
        A preview of the changes a workflow YAML definition would make, with a
        per-resource diff and a human-readable `rendered_plan`.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
          default: []
      type: object
      title: HTTPValidationError
    DeclarativePlanSummary:
      properties:
        add:
          type: integer
          title: Add
          default: 0
        change:
          type: integer
          title: Change
          default: 0
        destroy:
          type: integer
          title: Destroy
          default: 0
        replace:
          type: integer
          title: Replace
          default: 0
        noop:
          type: integer
          title: Noop
          default: 0
        total:
          type: integer
          title: Total
          default: 0
        has_changes:
          type: boolean
          title: Has Changes
          default: false
      type: object
      title: DeclarativePlanSummary
    DeclarativePlanResourceChange:
      properties:
        address:
          type: string
          title: Address
        target:
          type: string
          enum:
            - workflow
            - block
            - edge
          title: Target
        target_id:
          type: string
          title: Target Id
        name:
          type: string
          title: Name
        type:
          type: string
          enum:
            - workflow
            - edge
            - start_document
            - start_json
            - note
            - parse
            - edit
            - extract
            - split
            - classifier
            - conditional
            - api_call
            - function
            - while_loop
            - for_each
            - merge_dicts
            - while_loop_sentinel_start
            - while_loop_sentinel_end
            - for_each_sentinel_start
            - for_each_sentinel_end
          title: Type
          description: >-
            Resource kind for this plan entry. `workflow` and `edge` are flat
            singletons; for `target='block'` this carries the block's concrete
            type (e.g. `extract`, `api_call`) so the plan summary can render
            type-specific labels.
        actions:
          items:
            type: string
            enum:
              - create
              - update
              - delete
          type: array
          title: Actions
        summary:
          type: string
          title: Summary
        change:
          $ref: '#/components/schemas/DeclarativePlanChange'
        path:
          anyOf:
            - type: string
            - type: 'null'
          title: Path
      type: object
      required:
        - actions
        - address
        - change
        - name
        - summary
        - target
        - target_id
        - type
      title: DeclarativePlanResourceChange
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
          default: null
        ctx:
          type: object
          title: Context
          default: {}
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    DeclarativePlanChange:
      properties:
        before:
          anyOf:
            - {}
            - type: 'null'
          title: Before
        after:
          anyOf:
            - {}
            - type: 'null'
          title: After
        before_sensitive:
          title: Before Sensitive
          default: null
        after_sensitive:
          title: After Sensitive
          default: null
        field_changes:
          items:
            $ref: '#/components/schemas/DeclarativePlanFieldChange'
          type: array
          title: Field Changes
          default: []
      type: object
      title: DeclarativePlanChange
    DeclarativePlanFieldChange:
      properties:
        path:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Path
        path_display:
          type: string
          title: Path Display
        action:
          type: string
          enum:
            - create
            - update
            - delete
          title: Action
        before:
          anyOf:
            - {}
            - type: 'null'
          title: Before
        after:
          anyOf:
            - {}
            - type: 'null'
          title: After
        before_sensitive:
          type: boolean
          title: Before Sensitive
          default: false
        after_sensitive:
          type: boolean
          title: After Sensitive
          default: false
        unified_diff:
          anyOf:
            - type: string
            - type: 'null'
          title: Unified Diff
      type: object
      required:
        - action
        - path
        - path_display
      title: DeclarativePlanFieldChange
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````