# Actions

Manage test actions (rules) that automatically modify test behavior.

Actions allow you to:

* **Skip** tests that match certain conditions
* **Quarantine** flaky tests so their failures don't fail the run
* **Tag** tests with custom labels for organization

Each action has a **matcher** that defines which tests it applies to, based on conditions like test title, file path, tags, git branch, etc.

## List actions

> Get all actions for a project with optional filtering

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ProjectIdQuery":{"name":"projectId","in":"query","required":true,"description":"The project ID","schema":{"type":"string"}},"StatusFilter":{"name":"status","in":"query","required":false,"description":"Filter actions by status (can be specified multiple times)","schema":{"type":"array","items":{"$ref":"#/components/schemas/ActionStatus"}},"style":"form","explode":true},"SearchFilter":{"name":"search","in":"query","required":false,"description":"Search actions by name","schema":{"type":"string","maxLength":100}}},"schemas":{"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"ActionsListResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/ActionRecord"}}}},"ActionRecord":{"type":"object","required":["actionId","name","action","matcher","status","createdAt","createdBy"],"properties":{"actionId":{"type":"string","description":"Unique identifier for the action"},"name":{"type":"string","description":"Human-readable name for the action"},"description":{"type":"string","nullable":true,"description":"Optional description"},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"description":"Actions to perform when conditions match"},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"status":{"$ref":"#/components/schemas/ActionStatus"},"createdAt":{"type":"string","format":"date-time","description":"When the action was created"},"createdBy":{"type":"string","description":"Email of the user who created the action"},"updatedAt":{"type":"string","format":"date-time","nullable":true},"updatedBy":{"type":"string","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"disabledBy":{"type":"string","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"Action":{"oneOf":[{"$ref":"#/components/schemas/ActionSkip"},{"$ref":"#/components/schemas/ActionQuarantine"},{"$ref":"#/components/schemas/ActionTag"}]},"ActionSkip":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["skip"]}}},"ActionQuarantine":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["quarantine"]}}},"ActionTag":{"type":"object","required":["op","details"],"properties":{"op":{"type":"string","enum":["tag"]},"details":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags to add to matching tests"}}}}},"RuleMatcher":{"type":"object","required":["op","cond"],"properties":{"op":{"type":"string","enum":["AND","OR"],"description":"How to combine multiple conditions"},"cond":{"type":"array","items":{"$ref":"#/components/schemas/ActionMatcherCondition"},"minItems":1,"description":"List of conditions to match"}}},"ActionMatcherCondition":{"type":"object","required":["type","op"],"properties":{"type":{"$ref":"#/components/schemas/ConditionType"},"op":{"$ref":"#/components/schemas/ConditionOperator"},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"nullable":true,"description":"The value(s) to match against"}}},"ConditionType":{"type":"string","enum":["testId","project","title","file","git_branch","git_authorName","git_authorEmail","git_remoteOrigin","git_message","error_message","titlePath","annotation","tag"],"description":"The type of condition to match against.\n\n**Note:** Different condition types support different operators:\n- **Primitive types** (`testId`, `project`, `title`, `file`, `git_branch`, `git_authorName`, `git_authorEmail`, `git_remoteOrigin`, `git_message`): Support `eq`, `neq`, `any`, `empty`, `in`, `notIn`\n- **Complex types** (`error_message`, `titlePath`, `annotation`, `tag`): Support all operators including `inc`, `notInc`, `incAll`, `notIncAll`"},"ConditionOperator":{"type":"string","enum":["eq","neq","any","empty","in","notIn","inc","notInc","incAll","notIncAll"],"description":"The comparison operator:\n- `eq`: Equal to\n- `neq`: Not equal to\n- `any`: Matches any value (not null)\n- `empty`: Is empty or null\n- `in`: Value is in the list\n- `notIn`: Value is not in the list\n- `inc`: Includes substring (**only for**: error_message, titlePath, annotation, tag)\n- `notInc`: Does not include substring (**only for**: error_message, titlePath, annotation, tag)\n- `incAll`: Includes all values (**only for**: error_message, titlePath, annotation, tag)\n- `notIncAll`: Does not include all values (**only for**: error_message, titlePath, annotation, tag)"},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions":{"get":{"summary":"List actions","description":"Get all actions for a project with optional filtering","operationId":"listActions","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ProjectIdQuery"},{"$ref":"#/components/parameters/StatusFilter"},{"$ref":"#/components/parameters/SearchFilter"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionsListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Create action

> Create a new action for a project

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ProjectIdQuery":{"name":"projectId","in":"query","required":true,"description":"The project ID","schema":{"type":"string"}}},"schemas":{"CreateActionRequest":{"type":"object","required":["name","action","matcher"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string","maxLength":1000,"nullable":true},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"Action":{"oneOf":[{"$ref":"#/components/schemas/ActionSkip"},{"$ref":"#/components/schemas/ActionQuarantine"},{"$ref":"#/components/schemas/ActionTag"}]},"ActionSkip":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["skip"]}}},"ActionQuarantine":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["quarantine"]}}},"ActionTag":{"type":"object","required":["op","details"],"properties":{"op":{"type":"string","enum":["tag"]},"details":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags to add to matching tests"}}}}},"RuleMatcher":{"type":"object","required":["op","cond"],"properties":{"op":{"type":"string","enum":["AND","OR"],"description":"How to combine multiple conditions"},"cond":{"type":"array","items":{"$ref":"#/components/schemas/ActionMatcherCondition"},"minItems":1,"description":"List of conditions to match"}}},"ActionMatcherCondition":{"type":"object","required":["type","op"],"properties":{"type":{"$ref":"#/components/schemas/ConditionType"},"op":{"$ref":"#/components/schemas/ConditionOperator"},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"nullable":true,"description":"The value(s) to match against"}}},"ConditionType":{"type":"string","enum":["testId","project","title","file","git_branch","git_authorName","git_authorEmail","git_remoteOrigin","git_message","error_message","titlePath","annotation","tag"],"description":"The type of condition to match against.\n\n**Note:** Different condition types support different operators:\n- **Primitive types** (`testId`, `project`, `title`, `file`, `git_branch`, `git_authorName`, `git_authorEmail`, `git_remoteOrigin`, `git_message`): Support `eq`, `neq`, `any`, `empty`, `in`, `notIn`\n- **Complex types** (`error_message`, `titlePath`, `annotation`, `tag`): Support all operators including `inc`, `notInc`, `incAll`, `notIncAll`"},"ConditionOperator":{"type":"string","enum":["eq","neq","any","empty","in","notIn","inc","notInc","incAll","notIncAll"],"description":"The comparison operator:\n- `eq`: Equal to\n- `neq`: Not equal to\n- `any`: Matches any value (not null)\n- `empty`: Is empty or null\n- `in`: Value is in the list\n- `notIn`: Value is not in the list\n- `inc`: Includes substring (**only for**: error_message, titlePath, annotation, tag)\n- `notInc`: Does not include substring (**only for**: error_message, titlePath, annotation, tag)\n- `incAll`: Includes all values (**only for**: error_message, titlePath, annotation, tag)\n- `notIncAll`: Does not include all values (**only for**: error_message, titlePath, annotation, tag)"},"ActionResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"$ref":"#/components/schemas/ActionRecord"}}},"ActionRecord":{"type":"object","required":["actionId","name","action","matcher","status","createdAt","createdBy"],"properties":{"actionId":{"type":"string","description":"Unique identifier for the action"},"name":{"type":"string","description":"Human-readable name for the action"},"description":{"type":"string","nullable":true,"description":"Optional description"},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"description":"Actions to perform when conditions match"},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"status":{"$ref":"#/components/schemas/ActionStatus"},"createdAt":{"type":"string","format":"date-time","description":"When the action was created"},"createdBy":{"type":"string","description":"Email of the user who created the action"},"updatedAt":{"type":"string","format":"date-time","nullable":true},"updatedBy":{"type":"string","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"disabledBy":{"type":"string","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions":{"post":{"summary":"Create action","description":"Create a new action for a project","operationId":"createAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ProjectIdQuery"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateActionRequest"}}}},"responses":{"201":{"description":"Action created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Get action

> Get a single action by ID. The actionId is globally unique, so projectId is not required.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ActionIdPath":{"name":"actionId","in":"path","required":true,"description":"The action ID","schema":{"type":"string"}}},"schemas":{"ActionResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"$ref":"#/components/schemas/ActionRecord"}}},"ActionRecord":{"type":"object","required":["actionId","name","action","matcher","status","createdAt","createdBy"],"properties":{"actionId":{"type":"string","description":"Unique identifier for the action"},"name":{"type":"string","description":"Human-readable name for the action"},"description":{"type":"string","nullable":true,"description":"Optional description"},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"description":"Actions to perform when conditions match"},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"status":{"$ref":"#/components/schemas/ActionStatus"},"createdAt":{"type":"string","format":"date-time","description":"When the action was created"},"createdBy":{"type":"string","description":"Email of the user who created the action"},"updatedAt":{"type":"string","format":"date-time","nullable":true},"updatedBy":{"type":"string","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"disabledBy":{"type":"string","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"Action":{"oneOf":[{"$ref":"#/components/schemas/ActionSkip"},{"$ref":"#/components/schemas/ActionQuarantine"},{"$ref":"#/components/schemas/ActionTag"}]},"ActionSkip":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["skip"]}}},"ActionQuarantine":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["quarantine"]}}},"ActionTag":{"type":"object","required":["op","details"],"properties":{"op":{"type":"string","enum":["tag"]},"details":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags to add to matching tests"}}}}},"RuleMatcher":{"type":"object","required":["op","cond"],"properties":{"op":{"type":"string","enum":["AND","OR"],"description":"How to combine multiple conditions"},"cond":{"type":"array","items":{"$ref":"#/components/schemas/ActionMatcherCondition"},"minItems":1,"description":"List of conditions to match"}}},"ActionMatcherCondition":{"type":"object","required":["type","op"],"properties":{"type":{"$ref":"#/components/schemas/ConditionType"},"op":{"$ref":"#/components/schemas/ConditionOperator"},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"nullable":true,"description":"The value(s) to match against"}}},"ConditionType":{"type":"string","enum":["testId","project","title","file","git_branch","git_authorName","git_authorEmail","git_remoteOrigin","git_message","error_message","titlePath","annotation","tag"],"description":"The type of condition to match against.\n\n**Note:** Different condition types support different operators:\n- **Primitive types** (`testId`, `project`, `title`, `file`, `git_branch`, `git_authorName`, `git_authorEmail`, `git_remoteOrigin`, `git_message`): Support `eq`, `neq`, `any`, `empty`, `in`, `notIn`\n- **Complex types** (`error_message`, `titlePath`, `annotation`, `tag`): Support all operators including `inc`, `notInc`, `incAll`, `notIncAll`"},"ConditionOperator":{"type":"string","enum":["eq","neq","any","empty","in","notIn","inc","notInc","incAll","notIncAll"],"description":"The comparison operator:\n- `eq`: Equal to\n- `neq`: Not equal to\n- `any`: Matches any value (not null)\n- `empty`: Is empty or null\n- `in`: Value is in the list\n- `notIn`: Value is not in the list\n- `inc`: Includes substring (**only for**: error_message, titlePath, annotation, tag)\n- `notInc`: Does not include substring (**only for**: error_message, titlePath, annotation, tag)\n- `incAll`: Includes all values (**only for**: error_message, titlePath, annotation, tag)\n- `notIncAll`: Does not include all values (**only for**: error_message, titlePath, annotation, tag)"},"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/{actionId}":{"get":{"summary":"Get action","description":"Get a single action by ID. The actionId is globally unique, so projectId is not required.","operationId":"getAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ActionIdPath"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Update action

> Update an existing action. The actionId is globally unique, so projectId is not required.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ActionIdPath":{"name":"actionId","in":"path","required":true,"description":"The action ID","schema":{"type":"string"}}},"schemas":{"UpdateActionRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string","maxLength":1000,"nullable":true},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"Action":{"oneOf":[{"$ref":"#/components/schemas/ActionSkip"},{"$ref":"#/components/schemas/ActionQuarantine"},{"$ref":"#/components/schemas/ActionTag"}]},"ActionSkip":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["skip"]}}},"ActionQuarantine":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["quarantine"]}}},"ActionTag":{"type":"object","required":["op","details"],"properties":{"op":{"type":"string","enum":["tag"]},"details":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags to add to matching tests"}}}}},"RuleMatcher":{"type":"object","required":["op","cond"],"properties":{"op":{"type":"string","enum":["AND","OR"],"description":"How to combine multiple conditions"},"cond":{"type":"array","items":{"$ref":"#/components/schemas/ActionMatcherCondition"},"minItems":1,"description":"List of conditions to match"}}},"ActionMatcherCondition":{"type":"object","required":["type","op"],"properties":{"type":{"$ref":"#/components/schemas/ConditionType"},"op":{"$ref":"#/components/schemas/ConditionOperator"},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"nullable":true,"description":"The value(s) to match against"}}},"ConditionType":{"type":"string","enum":["testId","project","title","file","git_branch","git_authorName","git_authorEmail","git_remoteOrigin","git_message","error_message","titlePath","annotation","tag"],"description":"The type of condition to match against.\n\n**Note:** Different condition types support different operators:\n- **Primitive types** (`testId`, `project`, `title`, `file`, `git_branch`, `git_authorName`, `git_authorEmail`, `git_remoteOrigin`, `git_message`): Support `eq`, `neq`, `any`, `empty`, `in`, `notIn`\n- **Complex types** (`error_message`, `titlePath`, `annotation`, `tag`): Support all operators including `inc`, `notInc`, `incAll`, `notIncAll`"},"ConditionOperator":{"type":"string","enum":["eq","neq","any","empty","in","notIn","inc","notInc","incAll","notIncAll"],"description":"The comparison operator:\n- `eq`: Equal to\n- `neq`: Not equal to\n- `any`: Matches any value (not null)\n- `empty`: Is empty or null\n- `in`: Value is in the list\n- `notIn`: Value is not in the list\n- `inc`: Includes substring (**only for**: error_message, titlePath, annotation, tag)\n- `notInc`: Does not include substring (**only for**: error_message, titlePath, annotation, tag)\n- `incAll`: Includes all values (**only for**: error_message, titlePath, annotation, tag)\n- `notIncAll`: Does not include all values (**only for**: error_message, titlePath, annotation, tag)"},"ActionResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"$ref":"#/components/schemas/ActionRecord"}}},"ActionRecord":{"type":"object","required":["actionId","name","action","matcher","status","createdAt","createdBy"],"properties":{"actionId":{"type":"string","description":"Unique identifier for the action"},"name":{"type":"string","description":"Human-readable name for the action"},"description":{"type":"string","nullable":true,"description":"Optional description"},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"description":"Actions to perform when conditions match"},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"status":{"$ref":"#/components/schemas/ActionStatus"},"createdAt":{"type":"string","format":"date-time","description":"When the action was created"},"createdBy":{"type":"string","description":"Email of the user who created the action"},"updatedAt":{"type":"string","format":"date-time","nullable":true},"updatedBy":{"type":"string","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"disabledBy":{"type":"string","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/{actionId}":{"put":{"summary":"Update action","description":"Update an existing action. The actionId is globally unique, so projectId is not required.","operationId":"updateAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ActionIdPath"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateActionRequest"}}}},"responses":{"200":{"description":"Action updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Delete action

> Archive an action (soft delete). The actionId is globally unique, so projectId is not required.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ActionIdPath":{"name":"actionId","in":"path","required":true,"description":"The action ID","schema":{"type":"string"}}},"schemas":{"ActionDeleteResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"type":"object","required":["actionId","archived"],"properties":{"actionId":{"type":"string"},"archived":{"type":"boolean"}}}}},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/{actionId}":{"delete":{"summary":"Delete action","description":"Archive an action (soft delete). The actionId is globally unique, so projectId is not required.","operationId":"deleteAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ActionIdPath"}],"responses":{"200":{"description":"Action archived successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionDeleteResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Enable action

> Enable a disabled action. The actionId is globally unique, so projectId is not required.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ActionIdPath":{"name":"actionId","in":"path","required":true,"description":"The action ID","schema":{"type":"string"}}},"schemas":{"ActionResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"$ref":"#/components/schemas/ActionRecord"}}},"ActionRecord":{"type":"object","required":["actionId","name","action","matcher","status","createdAt","createdBy"],"properties":{"actionId":{"type":"string","description":"Unique identifier for the action"},"name":{"type":"string","description":"Human-readable name for the action"},"description":{"type":"string","nullable":true,"description":"Optional description"},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"description":"Actions to perform when conditions match"},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"status":{"$ref":"#/components/schemas/ActionStatus"},"createdAt":{"type":"string","format":"date-time","description":"When the action was created"},"createdBy":{"type":"string","description":"Email of the user who created the action"},"updatedAt":{"type":"string","format":"date-time","nullable":true},"updatedBy":{"type":"string","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"disabledBy":{"type":"string","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"Action":{"oneOf":[{"$ref":"#/components/schemas/ActionSkip"},{"$ref":"#/components/schemas/ActionQuarantine"},{"$ref":"#/components/schemas/ActionTag"}]},"ActionSkip":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["skip"]}}},"ActionQuarantine":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["quarantine"]}}},"ActionTag":{"type":"object","required":["op","details"],"properties":{"op":{"type":"string","enum":["tag"]},"details":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags to add to matching tests"}}}}},"RuleMatcher":{"type":"object","required":["op","cond"],"properties":{"op":{"type":"string","enum":["AND","OR"],"description":"How to combine multiple conditions"},"cond":{"type":"array","items":{"$ref":"#/components/schemas/ActionMatcherCondition"},"minItems":1,"description":"List of conditions to match"}}},"ActionMatcherCondition":{"type":"object","required":["type","op"],"properties":{"type":{"$ref":"#/components/schemas/ConditionType"},"op":{"$ref":"#/components/schemas/ConditionOperator"},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"nullable":true,"description":"The value(s) to match against"}}},"ConditionType":{"type":"string","enum":["testId","project","title","file","git_branch","git_authorName","git_authorEmail","git_remoteOrigin","git_message","error_message","titlePath","annotation","tag"],"description":"The type of condition to match against.\n\n**Note:** Different condition types support different operators:\n- **Primitive types** (`testId`, `project`, `title`, `file`, `git_branch`, `git_authorName`, `git_authorEmail`, `git_remoteOrigin`, `git_message`): Support `eq`, `neq`, `any`, `empty`, `in`, `notIn`\n- **Complex types** (`error_message`, `titlePath`, `annotation`, `tag`): Support all operators including `inc`, `notInc`, `incAll`, `notIncAll`"},"ConditionOperator":{"type":"string","enum":["eq","neq","any","empty","in","notIn","inc","notInc","incAll","notIncAll"],"description":"The comparison operator:\n- `eq`: Equal to\n- `neq`: Not equal to\n- `any`: Matches any value (not null)\n- `empty`: Is empty or null\n- `in`: Value is in the list\n- `notIn`: Value is not in the list\n- `inc`: Includes substring (**only for**: error_message, titlePath, annotation, tag)\n- `notInc`: Does not include substring (**only for**: error_message, titlePath, annotation, tag)\n- `incAll`: Includes all values (**only for**: error_message, titlePath, annotation, tag)\n- `notIncAll`: Does not include all values (**only for**: error_message, titlePath, annotation, tag)"},"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/{actionId}/enable":{"put":{"summary":"Enable action","description":"Enable a disabled action. The actionId is globally unique, so projectId is not required.","operationId":"enableAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ActionIdPath"}],"responses":{"200":{"description":"Action enabled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Disable action

> Disable an active action. The actionId is globally unique, so projectId is not required.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ActionIdPath":{"name":"actionId","in":"path","required":true,"description":"The action ID","schema":{"type":"string"}}},"schemas":{"ActionResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"$ref":"#/components/schemas/ActionRecord"}}},"ActionRecord":{"type":"object","required":["actionId","name","action","matcher","status","createdAt","createdBy"],"properties":{"actionId":{"type":"string","description":"Unique identifier for the action"},"name":{"type":"string","description":"Human-readable name for the action"},"description":{"type":"string","nullable":true,"description":"Optional description"},"action":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"description":"Actions to perform when conditions match"},"matcher":{"$ref":"#/components/schemas/RuleMatcher"},"status":{"$ref":"#/components/schemas/ActionStatus"},"createdAt":{"type":"string","format":"date-time","description":"When the action was created"},"createdBy":{"type":"string","description":"Email of the user who created the action"},"updatedAt":{"type":"string","format":"date-time","nullable":true},"updatedBy":{"type":"string","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"disabledBy":{"type":"string","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"expiresAfter":{"type":"string","format":"date-time","nullable":true}}},"Action":{"oneOf":[{"$ref":"#/components/schemas/ActionSkip"},{"$ref":"#/components/schemas/ActionQuarantine"},{"$ref":"#/components/schemas/ActionTag"}]},"ActionSkip":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["skip"]}}},"ActionQuarantine":{"type":"object","required":["op"],"properties":{"op":{"type":"string","enum":["quarantine"]}}},"ActionTag":{"type":"object","required":["op","details"],"properties":{"op":{"type":"string","enum":["tag"]},"details":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags to add to matching tests"}}}}},"RuleMatcher":{"type":"object","required":["op","cond"],"properties":{"op":{"type":"string","enum":["AND","OR"],"description":"How to combine multiple conditions"},"cond":{"type":"array","items":{"$ref":"#/components/schemas/ActionMatcherCondition"},"minItems":1,"description":"List of conditions to match"}}},"ActionMatcherCondition":{"type":"object","required":["type","op"],"properties":{"type":{"$ref":"#/components/schemas/ConditionType"},"op":{"$ref":"#/components/schemas/ConditionOperator"},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"nullable":true,"description":"The value(s) to match against"}}},"ConditionType":{"type":"string","enum":["testId","project","title","file","git_branch","git_authorName","git_authorEmail","git_remoteOrigin","git_message","error_message","titlePath","annotation","tag"],"description":"The type of condition to match against.\n\n**Note:** Different condition types support different operators:\n- **Primitive types** (`testId`, `project`, `title`, `file`, `git_branch`, `git_authorName`, `git_authorEmail`, `git_remoteOrigin`, `git_message`): Support `eq`, `neq`, `any`, `empty`, `in`, `notIn`\n- **Complex types** (`error_message`, `titlePath`, `annotation`, `tag`): Support all operators including `inc`, `notInc`, `incAll`, `notIncAll`"},"ConditionOperator":{"type":"string","enum":["eq","neq","any","empty","in","notIn","inc","notInc","incAll","notIncAll"],"description":"The comparison operator:\n- `eq`: Equal to\n- `neq`: Not equal to\n- `any`: Matches any value (not null)\n- `empty`: Is empty or null\n- `in`: Value is in the list\n- `notIn`: Value is not in the list\n- `inc`: Includes substring (**only for**: error_message, titlePath, annotation, tag)\n- `notInc`: Does not include substring (**only for**: error_message, titlePath, annotation, tag)\n- `incAll`: Includes all values (**only for**: error_message, titlePath, annotation, tag)\n- `notIncAll`: Does not include all values (**only for**: error_message, titlePath, annotation, tag)"},"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/{actionId}/disable":{"put":{"summary":"Disable action","description":"Disable an active action. The actionId is globally unique, so projectId is not required.","operationId":"disableAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ActionIdPath"}],"responses":{"200":{"description":"Action disabled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## List affected tests

> Get tests affected by actions (quarantine, skip, tag) for a project within a date range. Returns aggregated data grouped by test signature.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ProjectIdQuery":{"name":"projectId","in":"query","required":true,"description":"The project ID","schema":{"type":"string"}},"DateStartQuery":{"name":"date_start","in":"query","required":true,"description":"Start date in ISO 8601 format","schema":{"type":"string","format":"date-time"}},"DateEndQuery":{"name":"date_end","in":"query","required":true,"description":"End date in ISO 8601 format","schema":{"type":"string","format":"date-time"}},"PageQuery":{"name":"page","in":"query","required":false,"description":"Page number (0-indexed)","schema":{"type":"integer","minimum":0,"default":0}}},"schemas":{"ActionOp":{"type":"string","enum":["quarantine","skip","tag"],"description":"Action operation: quarantine, skip (do not run), or tag"},"ActionStatus":{"type":"string","enum":["active","disabled","archived","expired"],"description":"The current status of the action:\n- `active`: Action is enabled and will be applied to matching tests\n- `disabled`: Action is temporarily disabled\n- `archived`: Action has been soft-deleted\n- `expired`: Action has passed its expiration date"},"AffectedTestsListResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"type":"object","required":["list","count","total","nextPage"],"properties":{"list":{"type":"array","items":{"$ref":"#/components/schemas/AffectedTestListItem"}},"count":{"type":"integer","description":"Number of items in the current page"},"total":{"type":"integer","description":"Total number of affected tests"},"nextPage":{"oneOf":[{"type":"integer"},{"type":"boolean","enum":[false]}],"description":"Next page number (0-indexed), or false if no more pages"}}}}},"AffectedTestListItem":{"type":"object","required":["signature","title","specFile","actions","lastSeen","recordingCount"],"properties":{"signature":{"type":"string","description":"Unique test signature hash"},"title":{"type":"string","description":"Test title"},"specFile":{"type":"string","description":"Spec file path"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/AffectedTestAction"},"description":"Actions applied to this test"},"lastSeen":{"type":"string","format":"date-time","description":"Last time this test was seen"},"recordingCount":{"type":"integer","description":"Number of test recordings in the date range"}}},"AffectedTestAction":{"type":"object","required":["types","name","id","status","expiresAt","lastSeen","recordingCount"],"properties":{"types":{"type":"array","items":{"$ref":"#/components/schemas/ActionOp"},"description":"Action types (a single rule can have multiple operations)"},"name":{"type":"string","description":"Action/rule name"},"id":{"type":"string","description":"Action/rule ID"},"status":{"$ref":"#/components/schemas/ActionStatus"},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Expiration timestamp, or null if no expiration"},"tags":{"type":"array","items":{"type":"string"},"description":"Tag values (only present when types includes tag)"},"lastSeen":{"type":"string","format":"date-time","description":"Timestamp of last execution with this action (in the list date range)"},"recordingCount":{"type":"integer","description":"Number of test recordings with this action (in the list date range)"}}},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/tests":{"get":{"summary":"List affected tests","description":"Get tests affected by actions (quarantine, skip, tag) for a project within a date range. Returns aggregated data grouped by test signature.","operationId":"listAffectedTests","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ProjectIdQuery"},{"$ref":"#/components/parameters/DateStartQuery"},{"$ref":"#/components/parameters/DateEndQuery"},{"$ref":"#/components/parameters/PageQuery"},{"name":"limit","in":"query","required":false,"description":"Maximum number of results (1-100)","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"search","in":"query","required":false,"description":"Search by spec file path, test title, or action name (case-insensitive)","schema":{"type":"string","maxLength":100}},{"name":"action_type","in":"query","required":false,"description":"Filter by action types (action_type)","schema":{"type":"array","items":{"$ref":"#/components/schemas/ActionOp"}},"style":"form","explode":true},{"name":"action_id","in":"query","required":false,"description":"Filter by specific action ID (action_id)","schema":{"type":"string"}},{"name":"dir","in":"query","required":false,"description":"Sort direction for lastSeen (default: desc)","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"status","in":"query","required":false,"description":"Filter by action status. Accepts multiple values. Omit for all statuses.","schema":{"type":"array","items":{"$ref":"#/components/schemas/ActionStatus"}},"style":"form","explode":true}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffectedTestsListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Get affected test executions

> Get execution details for a specific affected test (by signature) within a date range. Returns individual test execution records with action info. Results are paginated with cursor-based pagination using the \`starting\_after\` and \`ending\_before\` query parameters. To list executions for a single rule across all tests, use \`GET /actions/{actionId}/tests\` instead of the removed \`action\_id\` query parameter.

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ProjectIdQuery":{"name":"projectId","in":"query","required":true,"description":"The project ID","schema":{"type":"string"}},"DateStartQuery":{"name":"date_start","in":"query","required":true,"description":"Start date in ISO 8601 format","schema":{"type":"string","format":"date-time"}},"DateEndQuery":{"name":"date_end","in":"query","required":true,"description":"End date in ISO 8601 format","schema":{"type":"string","format":"date-time"}},"StartingAfterQuery":{"name":"starting_after","in":"query","required":false,"description":"Cursor for pagination. Returns items after this cursor value.","schema":{"type":"string"}},"EndingBeforeQuery":{"name":"ending_before","in":"query","required":false,"description":"Cursor for pagination. Returns items before this cursor value.","schema":{"type":"string"}}},"schemas":{"AffectedTestExecutionsResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"type":"object","required":["executions","has_more"],"properties":{"executions":{"type":"array","items":{"$ref":"#/components/schemas/AffectedTestExecution"}},"has_more":{"type":"boolean","description":"Whether more execution rows exist after this page"}}}}},"AffectedTestExecution":{"type":"object","required":["cursor","runId","instanceId","testId","specFile","title","signature","branch","commitSha","commitMessage","executedAt"],"properties":{"cursor":{"type":"string","description":"Test document id; pass as starting_after to fetch the next page"},"runId":{"type":"string","description":"Run ID"},"instanceId":{"type":"string","description":"Instance ID"},"testId":{"type":"string","description":"Test ID"},"specFile":{"type":"string","description":"Spec file path for this test"},"title":{"type":"string","description":"Test title"},"signature":{"type":"string","description":"Stable test signature"},"branch":{"type":"string","nullable":true,"description":"Git branch"},"commitSha":{"type":"string","nullable":true,"description":"Git commit SHA"},"commitMessage":{"type":"string","nullable":true,"description":"Git commit message"},"executedAt":{"type":"string","format":"date-time","description":"When the test was executed"}}},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/tests/{signature}":{"get":{"summary":"Get affected test executions","description":"Get execution details for a specific affected test (by signature) within a date range. Returns individual test execution records with action info. Results are paginated with cursor-based pagination using the `starting_after` and `ending_before` query parameters. To list executions for a single rule across all tests, use `GET /actions/{actionId}/tests` instead of the removed `action_id` query parameter.","operationId":"getAffectedTestExecutions","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ProjectIdQuery"},{"name":"signature","in":"path","required":true,"description":"Test signature hash","schema":{"type":"string"}},{"$ref":"#/components/parameters/DateStartQuery"},{"$ref":"#/components/parameters/DateEndQuery"},{"name":"limit","in":"query","required":false,"description":"Maximum number of executions (1-50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":25}},{"$ref":"#/components/parameters/StartingAfterQuery"},{"$ref":"#/components/parameters/EndingBeforeQuery"},{"name":"search","in":"query","required":false,"description":"Search by action name (case-insensitive)","schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffectedTestExecutionsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Get affected test executions for an action

> List test executions where this rule/action was applied, within a date range. Same cursor pagination and filters as \`GET /actions/tests/{signature}\` except \`projectId\` is taken from the rule (after org ownership checks).

```json
{"openapi":"3.0.2","info":{"title":"Currents REST API","version":"1.0.0"},"tags":[{"name":"Actions","description":"Manage test actions (rules) that automatically modify test behavior.\n\nActions allow you to:\n- **Skip** tests that match certain conditions\n- **Quarantine** flaky tests so their failures don't fail the run\n- **Tag** tests with custom labels for organization\n\nEach action has a **matcher** that defines which tests it applies to,\nbased on conditions like test title, file path, tags, git branch, etc."}],"servers":[{"url":"https://api.currents.dev/v1","description":"Production API"},{"url":"https://api-staging.currents.dev/v1","description":"Staging API"},{"url":"http://localhost:4000/v1","description":"Local development"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication using Bearer token"}},"parameters":{"ActionIdPath":{"name":"actionId","in":"path","required":true,"description":"The action ID","schema":{"type":"string"}},"DateStartQuery":{"name":"date_start","in":"query","required":true,"description":"Start date in ISO 8601 format","schema":{"type":"string","format":"date-time"}},"DateEndQuery":{"name":"date_end","in":"query","required":true,"description":"End date in ISO 8601 format","schema":{"type":"string","format":"date-time"}},"StartingAfterQuery":{"name":"starting_after","in":"query","required":false,"description":"Cursor for pagination. Returns items after this cursor value.","schema":{"type":"string"}},"EndingBeforeQuery":{"name":"ending_before","in":"query","required":false,"description":"Cursor for pagination. Returns items before this cursor value.","schema":{"type":"string"}}},"schemas":{"AffectedTestExecutionsResponse":{"type":"object","required":["status","data"],"properties":{"status":{"type":"string","enum":["OK"]},"data":{"type":"object","required":["executions","has_more"],"properties":{"executions":{"type":"array","items":{"$ref":"#/components/schemas/AffectedTestExecution"}},"has_more":{"type":"boolean","description":"Whether more execution rows exist after this page"}}}}},"AffectedTestExecution":{"type":"object","required":["cursor","runId","instanceId","testId","specFile","title","signature","branch","commitSha","commitMessage","executedAt"],"properties":{"cursor":{"type":"string","description":"Test document id; pass as starting_after to fetch the next page"},"runId":{"type":"string","description":"Run ID"},"instanceId":{"type":"string","description":"Instance ID"},"testId":{"type":"string","description":"Test ID"},"specFile":{"type":"string","description":"Spec file path for this test"},"title":{"type":"string","description":"Test title"},"signature":{"type":"string","description":"Stable test signature"},"branch":{"type":"string","nullable":true,"description":"Git branch"},"commitSha":{"type":"string","nullable":true,"description":"Git commit SHA"},"commitMessage":{"type":"string","nullable":true,"description":"Git commit message"},"executedAt":{"type":"string","format":"date-time","description":"When the test was executed"}}},"ErrorResponse":{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","enum":["FAILED"]},"error":{"type":"string","description":"Error message"}}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/actions/{actionId}/tests":{"get":{"summary":"Get affected test executions for an action","description":"List test executions where this rule/action was applied, within a date range. Same cursor pagination and filters as `GET /actions/tests/{signature}` except `projectId` is taken from the rule (after org ownership checks).","operationId":"getAffectedTestExecutionsByAction","tags":["Actions"],"parameters":[{"$ref":"#/components/parameters/ActionIdPath"},{"$ref":"#/components/parameters/DateStartQuery"},{"$ref":"#/components/parameters/DateEndQuery"},{"name":"limit","in":"query","required":false,"description":"Maximum number of executions (1-50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":25}},{"$ref":"#/components/parameters/StartingAfterQuery"},{"$ref":"#/components/parameters/EndingBeforeQuery"},{"name":"search","in":"query","required":false,"description":"Search by action name (case-insensitive)","schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffectedTestExecutionsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```
