Validation Rules

Learn how to create, update, and manage validation rules on monday.com boards to enforce data quality through the API

🚧

Only available in API versions 2026-07 and later

Validation rules let you enforce data quality on monday.com boards by defining constraints on column values. Unlike required columns which simply mark a column as mandatory, validation rules support comparison operators, value ranges, and conditional logic.

This guide walks you through the validation rules API from simple constraints to conditional rules. By the end, you'll be able to programmatically enforce business rules like "amounts must be at least 5" or "if the status is Done, the description must be filled in."

Key concepts

How validation rules work

A validation rule has two parts:

PartRequiredDescription
thenYesThe constraint that must be satisfied. Defines what the column value should look like.
ifNoA condition that triggers the rule. When provided, the then constraint only applies when the if condition is met.

Rules without an if clause are non-conditional — they always apply. Rules with an if clause are conditional — they only apply when the condition is met.

Enforcement

Validation rules are enforced both in the monday.com interface and through the API. When you create or update items via mutations like create_item, change_simple_column_value, or change_column_values, the API checks active validation rules and rejects requests that violate them with a DATA_VALIDATIONS_ERROR error (422 status code).

The error response includes details about which columns failed validation:

{
  "errors": [
    {
      "message": "data_validation_error",
      "extensions": {
        "code": "DATA_VALIDATIONS_ERROR",
        "status_code": 422,
        "error_data": [
          {
            "itemId": null,
            "columnIds": ["numeric_mm1pddwd"],
            "message": "'Amount' must be at least [5]"
          }
        ]
      }
    }
  ]
}

Relationship to required columns

Validation rules and required columns are separate features that coexist on the same board:

  • Required columns (add_required_column / remove_required_column) mark a column as mandatory. The column must have a value, but there's no constraint on what that value is.
  • Validation rules (create_validation_rule / update_validation_rule / delete_validation_rule) define constraints on what values are acceptable.

Both appear in the validations query response — required columns in required_column_ids and rules in rules.

Prerequisites

  • API authentication token
  • A board ID (find it in the URL: monday.com/boards/{board_id})
  • Familiarity with the column IDs on your board (query boardscolumnsid)
  • Requests must include the API-Version: 2026-07 header
  • Pro or Enterprise monday.com account

Creating your first rule

Simple unconditional rule

Let's create a rule that requires a status column to be one of two specific values (label indices 1 and 2):

mutation {
  create_validation_rule(
    id: 1234567890,
    type: board,
    rule: {
      then: {
        operator: AND,
        groups: [{
          operator: ANY_OF,
          column_id: "status",
          compare_value: [1, 2]
        }]
      }
    }
  ) {
    id
    if
    then
  }
}

The response includes the generated rule ID:

{
  "data": {
    "create_validation_rule": {
      "id": "cd7f1b7b-452e-40d3-886c-346184ffee7e",
      "if": null,
      "then": {
        "operator": "AND",
        "groups": [
          {
            "operator": "ANY_OF",
            "column_id": "status",
            "compare_value": [1, 2]
          }
        ]
      }
    }
  }
}

Key things to note:

  • The then clause requires an operator (AND or OR) and a groups array of constraints
  • Each constraint targets a column_id with a comparison operator and optional compare_value
  • Non-conditional rules return null for the if field
  • The returned id is a UUID you'll use for updates and deletes

Numeric constraint

Require a numbers column to be at least 5:

mutation {
  create_validation_rule(
    id: 1234567890,
    type: board,
    rule: {
      then: {
        operator: AND,
        groups: [{
          operator: GREATER_THAN_OR_EQUALS,
          column_id: "numbers0",
          compare_value: [5]
        }]
      }
    }
  ) {
    id
    then
  }
}

Date range constraint

Require a date column to fall within a specific range:

mutation {
  create_validation_rule(
    id: 1234567890,
    type: board,
    rule: {
      then: {
        operator: AND,
        groups: [{
          operator: BETWEEN,
          column_id: "date0",
          compare_value: ["2026-01-01", "2026-12-31"]
        }]
      }
    }
  ) {
    id
    then
  }
}

Text constraint

Require a text column to contain a specific substring:

mutation {
  create_validation_rule(
    id: 1234567890,
    type: board,
    rule: {
      then: {
        operator: AND,
        groups: [{
          operator: CONTAINS_TEXT,
          column_id: "text0",
          compare_value: ["REQ-"]
        }]
      }
    }
  ) {
    id
    then
  }
}

Conditional rules

Conditional rules use an if clause to gate when the then constraint applies. This lets you build logic like "if the status is Done, then the description must be filled in."

Basic conditional rule

mutation {
  create_validation_rule(
    id: 1234567890,
    type: board,
    rule: {
      if: {
        operator: AND,
        groups: [{
          operator: ANY_OF,
          column_id: "status",
          compare_value: [1]
        }]
      },
      then: {
        operator: AND,
        groups: [{
          operator: IS_NOT_EMPTY,
          column_id: "text0"
        }]
      }
    }
  ) {
    id
    if
    then
  }
}
👍

IS_NOT_EMPTY in conditional rules

The IS_NOT_EMPTY operator is only available inside conditional rules (rules with an if clause). It cannot be used in non-conditional rules. Use it in the then clause to require a column to have a value when a condition is met.

Multiple then constraints

Conditional rules can enforce multiple constraints at once. If a condition is met, require both a numbers column and a date column to be filled:

mutation {
  create_validation_rule(
    id: 1234567890,
    type: board,
    rule: {
      if: {
        operator: AND,
        groups: [{
          operator: ANY_OF,
          column_id: "priority",
          compare_value: [1]
        }]
      },
      then: {
        operator: AND,
        groups: [
          {
            operator: IS_NOT_EMPTY,
            column_id: "numbers0"
          },
          {
            operator: IS_NOT_EMPTY,
            column_id: "date0"
          }
        ]
      }
    }
  ) {
    id
    if
    then
  }
}

Updating and deleting rules

Update a rule

Use update_validation_rule with the rule's ID. You must provide the full rule definition — partial updates are not supported:

mutation {
  update_validation_rule(
    id: 1234567890,
    type: board,
    rule_id: "cd7f1b7b-452e-40d3-886c-346184ffee7e",
    rule: {
      then: {
        operator: AND,
        groups: [{
          operator: GREATER_THAN_OR_EQUALS,
          column_id: "numbers0",
          compare_value: [10]
        }]
      }
    }
  ) {
    id
    if
    then
  }
}

Delete a rule

mutation {
  delete_validation_rule(
    id: 1234567890,
    type: board,
    rule_id: "cd7f1b7b-452e-40d3-886c-346184ffee7e"
  ) {
    id
  }
}

The mutation returns the deleted rule's data.

Reading validation rules

Query the validations endpoint to see all validation rules and required columns on a board:

query {
  validations(id: 1234567890) {
    required_column_ids
    rules
  }
}

The rules field returns a JSON object where each key is a rule ID and each value is the rule definition:

{
  "data": {
    "validations": {
      "required_column_ids": null,
      "rules": {
        "80d2c9d3-c93d-40be-9d34-b611241345b5": {
          "then": {
            "operator": "AND",
            "groups": [{
              "operator": "GREATER_THAN_OR_EQUALS",
              "column_id": "numbers0",
              "compare_value": [5]
            }]
          }
        },
        "31933592-171a-47ae-93a5-7a1c214fc9a3": {
          "if": {
            "operator": "AND",
            "groups": [{
              "operator": "ANY_OF",
              "column_id": "status",
              "compare_value": [1]
            }]
          },
          "then": {
            "operator": "AND",
            "groups": [{
              "operator": "IS_NOT_EMPTY",
              "column_id": "text0",
              "compare_value": []
            }]
          }
        }
      }
    }
  }
}
📘

NOTE

In the query response, conditional rules include both if and then keys. Non-conditional rules only have a then key (the if key is absent, not null). This differs from the mutation response where if is explicitly null.

Supported operators by column type

Not all operators work with all column types. Here's a summary of supported combinations for non-conditional rules:

Column TypeANY_OFNOT_ANY_OFGREATER_THANGREATER_THAN_OR_EQUALSLOWER_THANLOWER_THAN_OR_EQUALBETWEENCONTAINS_TEXTSTARTS_WITH_TEXTNOT_CONTAINS_TEXT
Status
Numbers
Text
Date
Rating

For conditional rules, the then clause additionally supports IS_NOT_EMPTY and IS_EMPTY across column types.

Constraints and limitations

ConstraintDescription
One non-conditional rule per columnA column can have at most one non-conditional rule.
No mixing rule typesA column cannot have both conditional and non-conditional rules.
Single if constraintConditional rules must have exactly one constraint in the if clause.
Single then for non-conditionalNon-conditional rules must have exactly one constraint in the then clause.
Multiple then for conditionalConditional rules can have multiple constraints in the then clause.
Pro/Enterprise onlyValidation rules require a Pro or Enterprise plan.
Enforced in UI and APIRules are enforced in both the monday.com UI and via the API. API requests that violate rules return a DATA_VALIDATIONS_ERROR (422).

Compare value formats

The compare_value array format varies by column type:

Column TypeOperatorcompare_valueNotes
StatusANY_OF[1, 2]Label indices as integers
NumbersGREATER_THAN[5]Single numeric value
TextCONTAINS_TEXT["search term"]Single string
DateBETWEEN["2026-01-01", "2026-12-31"]Two date strings in YYYY-MM-DD
DateGREATER_THAN["EXACT", "2026-01-01"]Prefix with "EXACT" for exact date
RatingANY_OF[4, 5]Rating values as integers
AnyIS_EMPTY(omit or empty)No compare_value needed
AnyIS_NOT_EMPTY(omit or empty)No compare_value needed

Next steps

If you have questions, post them in the monday developer community.