{
  "openapi": "3.1.0",
  "info": {
    "title": "Nexus CI API",
    "version": "1.0.0",
    "description": "Write test design, execution, deployment, environment and test-data evidence to one Nexus Jira project. Copy the installation-specific CI API URL from Nexus Project Settings and use it as the server URL.",
    "license": {
      "name": "Proprietary",
      "identifier": "LicenseRef-Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://replace-with-your-project-ci-api-url",
      "description": "Replace with the CI API URL shown in Nexus Project Settings"
    }
  ],
  "tags": [
    {
      "name": "CI operations",
      "description": "A bounded batch of write operations. Operation-level outcomes appear in the Nexus CI operation log."
    }
  ],
  "paths": {
    "/": {
      "post": {
        "operationId": "submitCiOperations",
        "summary": "Submit CI operations",
        "tags": [
          "CI operations"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "project",
            "in": "query",
            "required": true,
            "description": "Jira project key. It must match the API key's project.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Z][A-Z0-9_]{1,9}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CiBatch"
              },
              "examples": {
                "createAndReport": {
                  "summary": "Create a test and record a result",
                  "value": {
                    "operations": [
                      {
                        "op": "create-test-case",
                        "summary": "Login with valid credentials",
                        "automationKey": "AUTH-LOGIN-01",
                        "externalKey": "build-4821-login"
                      },
                      {
                        "op": "report-result",
                        "automationKey": "AUTH-LOGIN-01",
                        "status": "passed",
                        "environment": "staging"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. Check the Nexus CI operation log for operation-level outcomes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AcceptedResponse"
                },
                "example": {
                  "status": "accepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON or operation shape. Nothing is dispatched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RejectedResponse"
                },
                "example": {
                  "status": "rejected",
                  "reason": "invalid payload"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or wrong-project API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RejectedResponse"
                },
                "example": {
                  "status": "rejected",
                  "reason": "unauthorized"
                }
              }
            }
          },
          "413": {
            "description": "The body, 25-operation work budget or per-project rate guard was exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RejectedResponse"
                },
                "example": {
                  "status": "rejected",
                  "reason": "payload too large"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected failure while accepting the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "status": "error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Project-specific Nexus API key"
      }
    },
    "schemas": {
      "CiBatch": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "operations"
        ],
        "properties": {
          "operations": {
            "type": "array",
            "minItems": 1,
            "maxItems": 25,
            "items": {
              "$ref": "#/components/schemas/Operation"
            }
          }
        }
      },
      "Operation": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/CreateTestCase"
          },
          {
            "$ref": "#/components/schemas/UpdateTestCase"
          },
          {
            "$ref": "#/components/schemas/AddToCycle"
          },
          {
            "$ref": "#/components/schemas/AddCasesToCycle"
          },
          {
            "$ref": "#/components/schemas/SetRunAssignee"
          },
          {
            "$ref": "#/components/schemas/ReportResult"
          },
          {
            "$ref": "#/components/schemas/RecordDeployment"
          },
          {
            "$ref": "#/components/schemas/RecordEnvironmentEvent"
          },
          {
            "$ref": "#/components/schemas/RecordConfiguration"
          },
          {
            "$ref": "#/components/schemas/ReserveDataRows"
          },
          {
            "$ref": "#/components/schemas/ConsumeDataRows"
          },
          {
            "$ref": "#/components/schemas/ReleaseDataRows"
          }
        ],
        "discriminator": {
          "propertyName": "op"
        }
      },
      "Step": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "action": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 4000
          },
          "data": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 4000
          },
          "expected": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 4000
          }
        }
      },
      "CreateTestCase": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "summary"
        ],
        "properties": {
          "op": {
            "const": "create-test-case"
          },
          "summary": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "steps": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/Step"
            }
          },
          "preconditions": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000
          },
          "automationKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "externalKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Caller-supplied idempotency key."
          }
        }
      },
      "UpdateTestCase": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "testCaseKey"
        ],
        "properties": {
          "op": {
            "const": "update-test-case"
          },
          "testCaseKey": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "steps": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/Step"
            },
            "description": "Replaces the complete step table when supplied."
          },
          "preconditions": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000
          },
          "automationKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        }
      },
      "AddToCycle": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "testSetKey",
          "testCaseKey"
        ],
        "properties": {
          "op": {
            "const": "add-to-cycle"
          },
          "testSetKey": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "testCaseKey": {
            "$ref": "#/components/schemas/IssueKey"
          }
        }
      },
      "AddCasesToCycle": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "testSetKey",
          "testCaseKeys"
        ],
        "properties": {
          "op": {
            "const": "add-cases-to-cycle"
          },
          "testSetKey": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "testCaseKeys": {
            "type": "array",
            "minItems": 1,
            "maxItems": 25,
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/IssueKey"
            }
          }
        }
      },
      "SetRunAssignee": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "runKey",
          "accountId"
        ],
        "properties": {
          "op": {
            "const": "set-run-assignee"
          },
          "runKey": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "accountId": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128,
            "description": "Atlassian account id, or null to unassign.",
            "pattern": "^[A-Za-z0-9:_-]{1,128}$"
          }
        }
      },
      "ReportResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "automationKey",
          "status"
        ],
        "properties": {
          "op": {
            "const": "report-result"
          },
          "automationKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "status": {
            "type": "string",
            "enum": [
              "passed",
              "failed",
              "skipped",
              "blocked"
            ]
          },
          "actualResult": {
            "type": "string",
            "maxLength": 4000
          },
          "environment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "testSetKey": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "configurationId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        }
      },
      "RecordDeployment": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "environment",
          "version",
          "status",
          "externalId"
        ],
        "properties": {
          "op": {
            "const": "record-deployment"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "version": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "status": {
            "type": "string",
            "enum": [
              "success",
              "failed",
              "rolled_back"
            ]
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId128"
          },
          "release": {
            "type": "string",
            "maxLength": 100
          },
          "component": {
            "type": "string",
            "maxLength": 80
          },
          "build": {
            "type": "string",
            "maxLength": 100
          },
          "commit": {
            "type": "string",
            "maxLength": 40
          },
          "deployedAt": {
            "type": "string",
            "format": "date-time",
            "maxLength": 40,
            "description": "ISO-8601 timestamp, no more than five minutes in the future."
          },
          "evidenceUrl": {
            "type": "string",
            "format": "uri",
            "maxLength": 512,
            "pattern": "^[Hh][Tt][Tt][Pp][Ss]://"
          }
        }
      },
      "RecordEnvironmentEvent": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "environment",
          "type",
          "externalId"
        ],
        "properties": {
          "op": {
            "const": "record-environment-event"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "type": {
            "type": "string",
            "enum": [
              "refresh",
              "outage_start",
              "outage_end",
              "config_change",
              "health"
            ]
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId128"
          },
          "healthState": {
            "type": "string",
            "enum": [
              "healthy",
              "degraded",
              "down",
              "unknown"
            ]
          },
          "invalidatesResults": {
            "type": "boolean"
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "maxLength": 40,
            "description": "ISO-8601 timestamp, no more than five minutes in the future."
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "type": {
                  "const": "health"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "required": [
                "healthState"
              ],
              "properties": {
                "healthState": {
                  "type": "string",
                  "enum": [
                    "healthy",
                    "degraded",
                    "down",
                    "unknown"
                  ]
                }
              }
            },
            "else": {
              "properties": {
                "healthState": false
              }
            }
          }
        ]
      },
      "RecordConfiguration": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "environment",
          "entries",
          "externalId"
        ],
        "properties": {
          "op": {
            "const": "record-configuration"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          },
          "entries": {
            "type": "object",
            "maxProperties": 100,
            "propertyNames": {
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._:/-]{0,63}$",
              "maxLength": 64
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 256,
              "minLength": 1,
              "pattern": "^[^\\u0000-\\u001f\\u007f]+$"
            },
            "minProperties": 0
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId128"
          },
          "merge": {
            "type": "boolean"
          },
          "capturedAt": {
            "type": "string",
            "format": "date-time",
            "maxLength": 40,
            "description": "ISO-8601 timestamp, no more than five minutes in the future."
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "merge": {
                  "const": true
                }
              },
              "required": [
                "merge"
              ]
            },
            "then": {
              "properties": {
                "entries": {
                  "minProperties": 1
                }
              }
            }
          }
        ]
      },
      "ReserveDataRows": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "execution",
          "dataSet",
          "externalId"
        ],
        "properties": {
          "op": {
            "const": "reserve-data-rows"
          },
          "execution": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "dataSet": {
            "$ref": "#/components/schemas/Uuid"
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId100"
          },
          "count": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "rowKeys": {
            "$ref": "#/components/schemas/RowKeys"
          },
          "environment": {
            "$ref": "#/components/schemas/Environment"
          }
        },
        "description": "Supply exactly one of count or rowKeys.",
        "oneOf": [
          {
            "required": [
              "count"
            ],
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 1,
                "maximum": 200
              },
              "rowKeys": false
            }
          },
          {
            "required": [
              "rowKeys"
            ],
            "properties": {
              "count": false,
              "rowKeys": {
                "$ref": "#/components/schemas/RowKeys"
              }
            }
          }
        ]
      },
      "ConsumeDataRows": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "execution",
          "dataSet",
          "externalId"
        ],
        "properties": {
          "op": {
            "const": "consume-data-rows"
          },
          "execution": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "dataSet": {
            "$ref": "#/components/schemas/Uuid"
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId100"
          },
          "rowKeys": {
            "$ref": "#/components/schemas/RowKeys"
          }
        }
      },
      "ReleaseDataRows": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "op",
          "execution",
          "dataSet",
          "externalId"
        ],
        "properties": {
          "op": {
            "const": "release-data-rows"
          },
          "execution": {
            "$ref": "#/components/schemas/IssueKey"
          },
          "dataSet": {
            "$ref": "#/components/schemas/Uuid"
          },
          "externalId": {
            "$ref": "#/components/schemas/ExternalId100"
          },
          "rowKeys": {
            "$ref": "#/components/schemas/RowKeys"
          }
        }
      },
      "IssueKey": {
        "type": "string",
        "pattern": "^[A-Z][A-Z0-9_]+-\\d+$"
      },
      "Environment": {
        "type": "string",
        "minLength": 1,
        "maxLength": 100
      },
      "ExternalId128": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128
      },
      "ExternalId100": {
        "type": "string",
        "pattern": "^[A-Za-z0-9._-]{1,100}$"
      },
      "Uuid": {
        "type": "string",
        "format": "uuid"
      },
      "RowKeys": {
        "type": "array",
        "minItems": 1,
        "maxItems": 200,
        "uniqueItems": true,
        "items": {
          "type": "string",
          "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$"
        }
      },
      "AcceptedResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "const": "accepted"
          }
        }
      },
      "RejectedResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "reason"
        ],
        "properties": {
          "status": {
            "const": "rejected"
          },
          "reason": {
            "type": "string",
            "enum": [
              "invalid payload",
              "unauthorized",
              "payload too large"
            ]
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "const": "error"
          }
        }
      }
    }
  }
}
