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

# If/Else

> Tests a condition on the extracted data and sends the document down a True or a False branch. Free.

**If/Else** evaluates one condition against the fields an [Extract](/guides/nodes/extract) node produced, and routes the document to one of two branches: **True** when the condition holds, **False** when it does not. It transforms nothing. It lives in the **Logic** section of the Studio palette and is in **Beta**.

Use it to handle matching and non-matching documents differently: send only invoices over a threshold to a [Slack alert](/guides/nodes/slack-alert), or only documents that failed a [Validate](/guides/nodes/validate) rule.

## The node

<CodeGroup>
  ```json API theme={null}
  {
    "id": "if_else_1",
    "type": "if_else",
    "condition": { "type": "comparison", "left": "total", "op": ">", "right": { "source": "literal", "value": 10000 } }
  }
  ```

  ```python Python theme={null}
  import os
  from anyformat.sdk import Client
  from anyformat.workflow import (
      WorkflowDefinition, Edge,
      ParseNode, ExtractNode, ExtractionSchema, Schema,
      IfElseNode, ComparisonCheck,
  )
  from anyformat.workflow.nodes import SlackAlertNode

  client = Client(api_key=os.environ["ANYFORMAT_API_KEY"])

  workflow = client.create_workflow(WorkflowDefinition(
      name="Large invoices",
      nodes=[
          ParseNode(id="parse_1", type="parse"),
          ExtractNode(id="extract_1", type="extract", extraction_schema=ExtractionSchema(fields=[
              Schema.string("vendor_name", "Vendor name."),
              Schema.float("total", "Grand total."),
          ])),
          IfElseNode(id="if_else_1", type="if_else", condition=ComparisonCheck(
              type="comparison", left="total", op=">", right={"source": "literal", "value": 10000},
          )),
          SlackAlertNode(id="slack_1", type="slack_alert", channel_id="C0123ABC", channel_name="#finance",
              message_template="Large invoice from ${field.vendor_name}: ${field.total}", severity="warning"),
      ],
      edges=[
          Edge(source="parse_1", target="extract_1"),
          Edge(source="extract_1", target="if_else_1"),
          Edge(source="if_else_1", target="slack_1", branch="true"),
      ],
  ))
  ```

  ```typescript TypeScript theme={null}
  // The TypeScript builder has no ifElse() method yet.
  // Send the API JSON on this page to POST /v3/workflows/, or pass the same
  // graph to af.updateWorkflow(workflowId, definition) on an existing workflow.
  ```
</CodeGroup>

The Python builder (`client.workflow(...).parse().extract(...)`) has no `if_else()` verb. Build a `WorkflowDefinition` from the node classes instead, as above, and pass it to `create_workflow`. The TypeScript builder has no method either; send the JSON.

The edge that leaves If/Else names its branch: `"branch": "true"` or `"branch": "false"`.

```json theme={null}
{ "source": "extract_1", "target": "if_else_1" },
{ "source": "if_else_1", "target": "slack_1", "branch": "true" }
```

A condition names a field by the **name** you gave it on the Extract node. Studio names fields by their persistent id; both forms resolve at run time.

## In Studio

Click the If/Else node on the canvas to open its panel. The **Conditions** list holds one card per condition; with two or more, the **And** / **Or** toggle at the top decides how they combine. Each card has a subject (a field value, field math, a validation outcome, or an expression) and the assertion that completes "Check that the field…"; click **Save condition** when done. The node has two output handles on the canvas, **true** and **false**.

<img src="https://mintcdn.com/anyformat/G2lOO-2_Ah2kKl9r/images/studio-if-else-config.webp?fit=max&auto=format&n=G2lOO-2_Ah2kKl9r&q=85&s=694f502f1a38acc9522f20e1168e0c5f" alt="The If/Else node panel in Studio" width="512" height="271" data-path="images/studio-if-else-config.webp" />

## Options

| Field       | Type         | Default  | What it does                                                                           |
| ----------- | ------------ | -------- | -------------------------------------------------------------------------------------- |
| `condition` | check object | required | The condition to evaluate. One check, or an `all_of` / `any_of` combinator of several. |

The schema the API accepts is generated from the same source: [If/Else node schema](/api-reference-v3/node-schemas#if_else).

### Conditions

A condition is a **check**: the same closed set the [Validate](/guides/nodes/validate#checks) node uses, plus one kind that only exists here.

| Check                   | `type`              | What it tests                                                                             |
| ----------------------- | ------------------- | ----------------------------------------------------------------------------------------- |
| **Required**            | `required`          | The field is present and not empty.                                                       |
| **Number in range**     | `range`             | A numeric field is within `min` and `max`.                                                |
| **Date in range**       | `date`              | A date field is within `earliest` and `latest`.                                           |
| **Arithmetic**          | `arithmetic`        | A sum, difference, or product of fields equals another field.                             |
| **Comparison**          | `comparison`        | A field compares to a fixed value or another field.                                       |
| **One of**              | `one_of`            | The field's value is in an allowed set.                                                   |
| **Pattern**             | `regex`             | The field matches a regular expression.                                                   |
| **Confidence**          | `confidence`        | The field's extraction confidence compares to a threshold.                                |
| **Expression**          | `expression`        | A CEL expression over the whole extraction.                                               |
| **Validation outcome**  | `validation`        | An upstream Validate rule ended with `status` (`fail` by default).                        |
| **All of** / **Any of** | `all_of` / `any_of` | Every / at least one nested check holds. This is what the **And** / **Or** toggle writes. |

The wire shape of each check is on the [Validate](/guides/nodes/validate#check-payloads) page. The `validation` check has its own:

```jsonc theme={null}
// Route on the outcome of the upstream rule "totals-add-up". status: "fail" | "pass" | "inconclusive"
{ "type": "validation", "rule_id": "totals-add-up", "status": "fail" }

// Two conditions combined with And
{ "type": "all_of", "checks": [
  { "type": "validation", "rule_id": "totals-add-up", "status": "fail" },
  { "type": "range", "field": "total", "min": 1000, "max": null }
] }
```

A `validation` condition needs a [Validate](/guides/nodes/validate) node upstream that carries a rule with that `rule_id`. A rule id with no verdict for the document evaluates to inconclusive.

<Note>
  **When a condition can't be evaluated, the document takes the False branch.** If a field the condition refers to is missing, or a confidence check has no confidence score, the condition counts as *not met*, so the document goes down **False**, never **True**. This keeps a True-only branch (like an alert) from firing on data anyformat couldn't actually check. To handle those documents on their own path instead, use a separate, preliminary If/Else node that checks whether the field is **required**, and place the value condition on its True branch.
</Note>

## What it returns

Nothing in the run results. If/Else adds no section and changes no field. It decides which downstream nodes run for the document:

* The condition holds: the nodes on the **true** branch run.
* The condition fails, or cannot be evaluated: the nodes on the **false** branch run.

The **true** branch must have at least one node; the API rejects an If/Else with no `"branch": "true"` edge. The **false** branch may be left empty, and the document then stops there. On a workflow with a Split node, the condition is evaluated once per sub-document.

## Connects to

| Direction | Nodes                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------- |
| Fed by    | [Extract](/guides/nodes/extract), [Validate](/guides/nodes/validate)                                                |
| Feeds     | [Slack alert](/guides/nodes/slack-alert), on either branch. [Email alert](/guides/nodes/email-alert) once it ships. |

An [Extract](/guides/nodes/extract) cannot sit after an If/Else today. The API rejects the edge (`an extract node cannot sit downstream of an if_else`) and Studio does not offer it. A second extraction pass on a branch is planned, not available.

## Billing

Free. If/Else runs no model and bills no credits. Full price list: [How credits work](/concepts/how-credits-work).

## Examples

* [Invoice processing](/examples/invoice-processing): add the If/Else on this page after the Extract to flag invoices over 10,000.
* [Contract analysis](/examples/contract-analysis): route contracts whose expiry date is on or before today to an alert with a `date` condition (`"latest": "today"`).
