---
updatedAt: 2026-05-28T15:59:25.000Z
agentTools:
  projectIndex: https://developers.qase.io/llms.txt
---

# Update test case

This method updates a test case.


# OpenAPI definition

````json
{
  "openapi": "3.0.0",
  "info": {
    "title": "Qase.io TestOps API v1",
    "description": "Qase TestOps API v1 Specification.\n\n## Rate limiting\n\nRequests are rate limited per workspace (shared across all API tokens of the\nworkspace). The exact limit depends on your subscription plan.\n\nEvery response advertises the current limit state through headers:\n\n- `RateLimit` and `RateLimit-Policy` — IETF rate-limit headers describing the\n  active policies and how much of each one is left.\n- `X-RateLimit-Limit` — maximum number of requests allowed in the window.\n- `X-RateLimit-Remaining` — requests left in the current window.\n- `X-RateLimit-Reset` — Unix timestamp at which the window resets.\n\nTwo policies apply at the same time. `rpm` caps the sustained rate over 60\nseconds. `burst` caps a short spike over 10 seconds. A request is served only\nwhen both policies allow it.\n\nExample headers on a served request, for a plan with a 600 rpm limit:\n\n```\nRateLimit-Policy: \"rpm\";q=600;w=60, \"burst\";q=100;w=10\nRateLimit: \"rpm\";r=412;t=37, \"burst\";r=88;t=2\nX-RateLimit-Limit: 100\nX-RateLimit-Remaining: 88\nX-RateLimit-Reset: 1756742400\n```\n\nIn `RateLimit-Policy`, `q` is the quota and `w` is the window in seconds. In\n`RateLimit`, `r` is the requests left and `t` is the seconds until that policy\nfrees a slot.\n\nThe `X-RateLimit-*` headers are a single-number mirror for older clients. They\nreport whichever of the two policies is closer to its limit, so they can show\nthe burst quota while a spike is in progress, as in the example above.\n\nWhen the limit is exceeded the API responds with `429 Too Many Requests`, a\n`Retry-After` header (seconds to wait before retrying), and the body:\n\n```\nRetry-After: 12\n```\n\n```json\n{\n  \"status\": false,\n  \"errorMessage\": \"API rate limit exceeded.\"\n}\n```\n",
    "termsOfService": "https://qase.io/terms",
    "version": "1.0.0",
    "contact": {
      "name": "Qase.io",
      "url": "https://qase.io",
      "email": "support@qase.io"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "https://github.com/qase-tms/specs/blob/master/LICENSE"
    }
  },
  "tags": [
    {
      "name": "cases"
    }
  ],
  "servers": [
    {
      "url": "https://api.qase.io/v1",
      "description": "The production API server."
    }
  ],
  "paths": {
    "/case/{code}/{id}": {
      "patch": {
        "operationId": "update-case",
        "tags": [
          "cases"
        ],
        "summary": "Update test case",
        "description": "This method updates a test case.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Code"
          },
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestCaseUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A Test Case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          },
          "404": {
            "description": "Not Found."
          },
          "422": {
            "description": "Unprocessable Entity."
          },
          "429": {
            "description": "Too Many Requests."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AttachmentHashList": {
        "type": "array",
        "description": "A list of Attachment hashes.",
        "items": {
          "type": "string"
        }
      },
      "DefectUpdate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "actual_result": {
            "type": "string"
          },
          "severity": {
            "type": "integer"
          },
          "milestone_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "custom_field": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Custom field values keyed by the field's project-scoped `internal_id`\n(see `GET /custom_field`). Values are always **scalar strings**; arrays,\nobjects or non-scalars are rejected.\n\n| Field type           | Value format                              | Example                 |\n|----------------------|-------------------------------------------|-------------------------|\n| `string`, `text`     | Plain string                              | `\"hello\"`               |\n| `number`             | Numeric string                            | `\"42\"`                  |\n| `url`                | Valid URL                                 | `\"https://qase.io\"`     |\n| `datetime`           | Absolute date (ISO 8601 recommended)      | `\"2026-04-29T15:00:00Z\"`|\n| `selectbox`, `radio` | Option `id` as string                     | `\"1\"`                   |\n| `multiselect`        | Comma-separated option `id`s (no spaces)  | `\"1,2,3\"`               |\n| `checkbox`           | `\"1\"` to check, `\"\"` to uncheck           | `\"1\"`                   |\n| `user`               | Team member `internal_id` as string       | `\"42\"`                  |\n\nPartial update: only fields present in the payload are validated; required\nfields not included are not enforced. Send `\"\"` to clear a value. Unknown\n`internal_id`s are rejected; option-based values must reference an existing\noption.\n\nNote: a `required` checkbox without a default cannot be unchecked via the API\n— set a default or clear `required` in workspace settings.\n"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ReviewCaseData": {
        "type": "object",
        "description": "The test case fields proposed by the review.",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "preconditions": {
            "type": "string",
            "nullable": true
          },
          "postconditions": {
            "type": "string",
            "nullable": true
          },
          "severity": {
            "type": "integer",
            "nullable": true
          },
          "priority": {
            "type": "integer",
            "nullable": true
          },
          "behavior": {
            "type": "integer",
            "nullable": true
          },
          "type": {
            "type": "integer",
            "nullable": true
          },
          "layer": {
            "type": "integer",
            "nullable": true
          },
          "is_flaky": {
            "type": "integer",
            "nullable": true
          },
          "is_muted": {
            "type": "boolean",
            "description": "Mute state of the proposed test case."
          },
          "suite_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "milestone_id": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "is_manual": {
            "type": "boolean",
            "description": "`true` if the case is manual, `false` if it is automated."
          },
          "is_to_be_automated": {
            "type": "boolean",
            "description": "`true` if a manual case is planned to be automated."
          },
          "status": {
            "type": "integer",
            "nullable": true
          },
          "steps_type": {
            "type": "string",
            "enum": [
              "classic",
              "gherkin"
            ],
            "description": "Format of the steps field. Omit to keep the current one, `classic` for a new-case draft; changing it requires sending `steps` in the same request."
          },
          "attachments": {
            "$ref": "#/components/schemas/AttachmentHashList"
          },
          "steps": {
            "type": "array",
            "description": "For gherkin steps send the scenario in `value`.",
            "items": {
              "$ref": "#/components/schemas/ReviewStepData"
            }
          },
          "tags": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            }
          },
          "parameters": {
            "type": "array",
            "nullable": true,
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "description": "Shared parameter",
                  "properties": {
                    "shared_id": {
                      "type": "string",
                      "format": "uuid"
                    }
                  },
                  "required": [
                    "shared_id"
                  ]
                },
                {
                  "type": "object",
                  "description": "Single parameter",
                  "properties": {
                    "title": {
                      "type": "string"
                    },
                    "values": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "title",
                    "values"
                  ]
                },
                {
                  "type": "object",
                  "description": "Group parameter",
                  "properties": {
                    "items": {
                      "type": "array",
                      "minItems": 2,
                      "items": {
                        "$ref": "#/components/schemas/ReviewCaseData/properties/parameters/items/oneOf/1"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              ]
            }
          },
          "custom_field": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DefectUpdate/properties/custom_field"
              }
            ],
            "description": "Map of custom field ID to value. A `create` review must carry every required custom field. An `edit` review is validated against the current test case, so send only the fields the proposal changes."
          }
        }
      },
      "TestCaseUpdate": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "preconditions": {
            "type": "string"
          },
          "postconditions": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "maxLength": 255
          },
          "severity": {
            "type": "integer"
          },
          "priority": {
            "type": "integer"
          },
          "behavior": {
            "type": "integer"
          },
          "type": {
            "type": "integer"
          },
          "layer": {
            "type": "integer"
          },
          "is_flaky": {
            "type": "integer"
          },
          "suite_id": {
            "type": "integer",
            "format": "int64"
          },
          "milestone_id": {
            "type": "integer",
            "format": "int64"
          },
          "automation": {
            "type": "integer",
            "deprecated": true,
            "description": "Deprecated, use `isManual` and `isToBeAutomated` instead. Encodes the test case automation state as a single integer: `0` = manual, `1` = manual planned to be automated, `2` = automated. If both `automation` and `isManual`/`isToBeAutomated` are provided, `isManual` and `isToBeAutomated` take precedence."
          },
          "isManual": {
            "type": "boolean",
            "description": "`true` if the case is manual, `false` if it is automated. Combined with `isToBeAutomated`, replaces the deprecated `automation` field."
          },
          "isToBeAutomated": {
            "type": "boolean",
            "description": "`true` if a manual case is planned to be automated, `false` otherwise. Only meaningful when `isManual` is `true`; ignored when `isManual` is `false`."
          },
          "status": {
            "type": "integer"
          },
          "steps_type": {
            "type": "string",
            "enum": [
              "classic",
              "gherkin"
            ],
            "default": "classic",
            "description": "Determines the format of the steps field. When \"classic\", steps use the standard action/expected_result/data format. When \"gherkin\", steps use the {value: \"Given...\\nWhen...\\nThen...\"} format."
          },
          "attachments": {
            "$ref": "#/components/schemas/AttachmentHashList"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestStepCreate"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "params": {
            "type": "object",
            "nullable": true,
            "deprecated": true,
            "description": "Deprecated, use `parameters` instead.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "nullable": false
            }
          },
          "parameters": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/ReviewCaseData/properties/parameters/items"
            }
          },
          "custom_field": {
            "$ref": "#/components/schemas/DefectUpdate/properties/custom_field"
          }
        }
      },
      "TestStepCreate": {
        "type": "object",
        "description": "When `steps_type` is `gherkin` only the scenario text is read from a step. A non-empty `expected_result`, `data`, `attachments`, `shared` or nested `steps` is rejected, and so is sending the scenario in `value` and `action` at once.",
        "properties": {
          "action": {
            "type": "string",
            "description": "Step action text. Used for classic steps. For gherkin steps, use the \"value\" property instead."
          },
          "shared": {
            "type": "string",
            "description": "Hash of an existing shared step to insert at this position."
          },
          "expected_result": {
            "type": "string"
          },
          "data": {
            "type": "string"
          },
          "value": {
            "type": "string",
            "description": "Gherkin scenario text. Used when steps_type is \"gherkin\". Example: \"Given a user exists\\nWhen they log in\\nThen they see the dashboard\""
          },
          "position": {
            "type": "integer",
            "deprecated": true
          },
          "attachments": {
            "$ref": "#/components/schemas/AttachmentHashList"
          },
          "steps": {
            "type": "array",
            "description": "Nested steps may be passed here. Use same structure for them.",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "IdResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Response"
          },
          {
            "type": "object",
            "properties": {
              "result": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer",
                    "format": "int64"
                  }
                }
              }
            }
          }
        ]
      },
      "Response": {
        "type": "object",
        "properties": {
          "status": {
            "type": "boolean"
          }
        }
      }
    },
    "securitySchemes": {
      "TokenAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Token"
      }
    },
    "parameters": {
      "Code": {
        "name": "code",
        "in": "path",
        "description": "Code of project, where to search entities.",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 2,
          "maxLength": 10
        }
      },
      "Id": {
        "name": "id",
        "in": "path",
        "description": "Identifier.",
        "required": true,
        "schema": {
          "type": "integer"
        }
      }
    }
  },
  "security": [
    {
      "TokenAuth": []
    }
  ]
}
````