---
title: "Roll a flow back to an earlier version"
method: POST
path: "/external/v1/flows/{flow_id}/versions/{number}/restore"
tags: ["Flows"]
---

# Roll a flow back to an earlier version

`POST /external/v1/flows/{flow_id}/versions/{number}/restore`

## Request

- Base URL: `https://api.databar.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.databar.ai/external/v1/flows/{flow_id}/versions/{number}/restore`
- Auth: API key in header `x-apikey`

Make an older version current.

Nothing is overwritten: the old config is written as a new version, so the
rollback is itself revertible. A version that no longer validates — its
enrichment was deleted, its dataset changed — is refused with the reasons.

## Path parameters

- `flow_id` string, required
- `number` integer, required

## Request body

- RestoreFlowVersionIn
  - `internal_version` string, nullable: Optional concurrency check, same semantics as on update.

## Response `200`

OK

- RestoreFlowVersionOut
  - `flow` FlowDetailOut, required: ``FlowOut`` plus the pieces an editing client needs. Without ``config`` and ``internal_version`` a caller cannot do a read-modify-write at all, which is why the API could only run flows.
    - `id` string, required
    - `name` string, required
    - `description` string, required
    - `inputs` FlowInputOut[], required
      - `id` string, required
      - `description` string, required
      - `type` string, required
      - `required` boolean, required
    - `outputs` FlowOutputOut[], required
      - `id` string, required
      - `key` string, nullable
      - `name` string, nullable
      - `response_field_id` integer, nullable
    - `created_at` string, required
    - `updated_at` string, required
    - `config` FlowDefinition, required
      - `inputs` FlowDefFunctionInput[]
        - `id` string, required
        - `description` string
        - `type` string: Same vocabulary as RequestParam.type_data.
        - `required` boolean: If true, input_bindings must include this id when attaching the function to a table.
      - `nodes` union[], required
        - union
          - FlowDefEnrichmentNode
            - `id` string, required
            - `type` 'enrichment'
            - `label` string
            - `on_error` 'stop' | 'skip': What to do when the enrichment call fails: stop the whole run or skip this node.
            - `on_no_data` 'stop' | 'skip': What to do when the enrichment returns no data: stop the run or skip this node.
            - `data` FlowDefEnrichmentNodeData, required
              - …
          - FlowDefConditionNode
            - `id` string, required
            - `type` 'condition'
            - `label` string
            - `on_error` 'stop' | 'skip': What to do when formula evaluation raises an exception.
            - `data` FlowDefConditionNodeData, required
              - …
          - FlowDefJqNode: Transform a JSON value using a jq expression.
            - `id` string, required
            - `type` 'jq'
            - `label` string
            - `on_error` 'stop' | 'skip': What to do when the jq program raises: stop the run or skip this node.
            - `data` FlowDefJqNodeData, required: Data for a JQ transform node — runs a jq expression on one or more JSON inputs.
              - …
          - FlowDefMergeNode: Concatenate multiple string inputs into a single value.
            - `id` string, required
            - `type` 'merge'
            - `label` string
            - `on_error` 'stop' | 'skip'
            - `data` FlowDefMergeNodeData, required: Data for a merge/concatenate node.
              - …
          - FlowDefMathFunctionNode: Evaluate an arithmetic expression with SymPy (Math Function tool).
            - `id` string, required
            - `type` 'math_function'
            - `label` string
            - `on_error` 'stop' | 'skip'
            - `data` FlowDefMathFunctionNodeData, required: Data for a Math Function node — evaluates a SymPy arithmetic expression.
              - …
          - FlowDefTableLookupNode: Query another Databar table and return matching rows as JSON.
            - `id` string, required
            - `type` 'table_lookup'
            - `label` string
            - `on_error` 'stop' | 'skip'
            - `data` FlowDefTableLookupNodeData, required: Data for a table-lookup node — queries another Databar table.
              - …
          - FlowDefWaterfallNode: Run a multi-provider waterfall enrichment pipeline.
            - `id` string, required
            - `type` 'waterfall'
            - `label` string
            - `on_error` 'stop' | 'skip': What to do when the waterfall fails: stop the run or skip this node.
            - `on_no_data` 'stop' | 'skip': What to do when no provider returns data: stop the run or skip this node.
            - `data` FlowDefWaterfallNodeData, required: Data for a waterfall node — runs ordered enrichments until one succeeds.
              - …
      - `named_outputs` FlowDefNamedFlowOutput[], nullable
        - `id` string, required
        - `key` string, required
        - `name` string, required
        - `source` FlowDefFlowOutputSource
          - `node_id` string, required
          - `ref` string, nullable
        - `mapping` FlowDefFlowOutput: Flow-level output mapping: reshape the run result into a custom shape. Two mutually-exclusive modes: * :attr:`fields` — structured mapping. Each entry is a :data:`NodeInput` whose ``id`` becomes the key in the returned ``outputs`` object. * :attr:`template` — a raw JSON string the user writes directly, with ``{{ input.x }}`` / ``{{ nodes.id.port }}`` tokens resolved at runtime. Supports arbitrary nested JSON, not just a flat object. When ``FlowDefinition.output`` is set, the executor returns the reshaped result instead of the raw namespaced ``{node_id: {port: value}}`` dict.
          - `fields` union[]: Output field bindings; each `id` is the key in the returned outputs object.
            - union
              - …
          - `template` string, nullable: Raw JSON template with `{{ input.x }}` / `{{ nodes.id.port }}` tokens. Overrides `fields`.
        - `combine` string[]
        - `combine_fields` FlowDefCombinedOutputField[]
          - `id` string, required
          - `output_id` string, required
          - `path` string
      - `output` FlowDefFlowOutput: Flow-level output mapping: reshape the run result into a custom shape. Two mutually-exclusive modes: * :attr:`fields` — structured mapping. Each entry is a :data:`NodeInput` whose ``id`` becomes the key in the returned ``outputs`` object. * :attr:`template` — a raw JSON string the user writes directly, with ``{{ input.x }}`` / ``{{ nodes.id.port }}`` tokens resolved at runtime. Supports arbitrary nested JSON, not just a flat object. When ``FlowDefinition.output`` is set, the executor returns the reshaped result instead of the raw namespaced ``{node_id: {port: value}}`` dict.
        - `fields` union[]: Output field bindings; each `id` is the key in the returned outputs object.
          - union
            - FlowDefInputRef: Binds a node input slot to a function-level input.
              - …
            - FlowDefNodeRef: Binds a node input slot to an output of another node.
              - …
            - FlowDefStaticRef: Binds a node input slot to a hardcoded value.
              - …
            - FlowDefStaticWithRefsInput: Binds a node input slot to a template string with ``{ref_id}`` substitutions. Used for prompt-text style fields where the resolved value is a literal with references interpolated inline, e.g. ``"Tell me about {company}"`` where ``company`` is a nested ref to a function input or upstream node output. Tokens supported: * ``{name}`` — required ref; raises ``ValueError`` if no matching entry in :attr:`refs` resolves to a value (i.e. the ref is missing or the upstream port is unset). An unmatched name that equals a function input id is treated as that input (MCP/UI often persist ``{domain}`` with empty refs). * ``{?name}`` — optional ref; falls back to ``""`` when missing. The token character set matches the table-side rich editor (``[a-zA-Z0-9_.]``) so prompts copied from a table workflow keep working.
              - …
        - `template` string, nullable: Raw JSON template with `{{ input.x }}` / `{{ nodes.id.port }}` tokens. Overrides `fields`.
    - `ui` object, required
    - `internal_version` string, required
  - `version` FlowVersionOut, required
    - `number` integer, required
    - `name` string, required
    - `description` string, required
    - `changed_fields` string[], required
    - `source` string, required: Where the edit came from: ui, api, mcp, admin or system.
    - `created_at` string, required
    - `created_by` string, nullable, required
    - `restored_from` integer, nullable: Version this one was restored from, if it came from a rollback.

---

[API](https://skmtc.dev/databar/apis/external-api.md) - [All operations](https://skmtc.dev/databar/apis/external-api/llms.txt) - [OpenAPI document](https://skmtc.dev/databar/apis/external-api/revisions/efe15f8bb9bb?raw)
