{
  "openapi": "3.0.2",
  "info": {
    "title": "MobileBoost API",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.mobileboost.io"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/tests": {
      "get": {
        "summary": "Get tests",
        "description": "Retrieve test cases for your organisation. Filter by test ID, title, tags, or folder.",
        "operationId": "get_tests",
        "parameters": [
          {
            "required": false,
            "schema": {
              "title": "Test ID",
              "type": "string"
            },
            "name": "testId",
            "in": "query"
          },
          {
            "required": false,
            "schema": {
              "title": "Test IDs",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "name": "testIds",
            "in": "query"
          },
          {
            "required": false,
            "schema": {
              "title": "Title",
              "type": "string"
            },
            "name": "title",
            "in": "query"
          },
          {
            "required": false,
            "schema": {
              "title": "Tags",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "name": "tags",
            "in": "query"
          },
          {
            "required": false,
            "schema": {
              "title": "Folder ID",
              "type": "string"
            },
            "description": "Only the tests filed in this folder. `GET /tests/folders` has the ids.",
            "name": "folderId",
            "in": "query"
          },
          {
            "required": false,
            "schema": {
              "title": "Include subfolders",
              "type": "boolean",
              "default": false
            },
            "description": "With `folderId`, also return the tests in that folder's subfolders.",
            "name": "includeSubfolders",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create test",
        "description": "Create a new test case with natural-language commands.",
        "operationId": "create_test",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Create"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "testId": {
                      "type": "string",
                      "description": "The unique identifier of the created test"
                    }
                  }
                },
                "example": {
                  "testId": "xMIt964RUpAB95b6YI2F"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update test",
        "description": "Update the commands of an existing test case.",
        "operationId": "update_test",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Update"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete test",
        "description": "Delete one or more test cases by ID.",
        "operationId": "delete_test",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Delete"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/tests/execute": {
      "post": {
        "summary": "Execute tests",
        "description": "Execute one or more tests on a device. Provide the test as inline commands (JSON or markdown format per the input requirements), or reference existing test IDs. Supports device configuration, launch parameters, and iteration control.",
        "operationId": "execute_tests",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecuteTest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "A human-readable message describing the result of the request."
                    },
                    "test_suite_ids": {
                      "type": "array",
                      "description": "The IDs of the test suite runs that were created. Use these with `GET /suite/{suite_id}/status` to poll for results.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "status": {
                      "type": "string",
                      "description": "The initial status of the created test suite runs."
                    }
                  },
                  "required": [
                    "message",
                    "test_suite_ids",
                    "status"
                  ]
                },
                "example": {
                  "message": "Test suite runs created",
                  "test_suite_ids": [
                    "b1111111df174791a93e560390ea7e65"
                  ],
                  "status": "running"
                }
              }
            }
          }
        }
      }
    },
    "/tests/generate": {
      "post": {
        "summary": "Generate test automation",
        "description": "Write the automation code for a test that has a description but no working test file yet. Explores the app on a device, writes the test, verifies it by running it several times in a row, and commits it to the organisation's test repository, after which the test is runnable via `POST /tests/execute`. By default this targets the newest build uploaded for every platform the organisation has one for; pass `uploadId`, `bundleId`, or `platform` to narrow that. Generation is fire-and-forget: it queues on the organisation's existing device slots and the response returns as soon as the work is dispatched, not once it finishes.",
        "operationId": "generate_tests",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateTests"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "started": {
                      "type": "array",
                      "description": "The generation run that was dispatched immediately, for the first platform.",
                      "items": {
                        "type": "object"
                      }
                    },
                    "queued": {
                      "type": "array",
                      "description": "Platforms queued to start once the first platform's generation finishes (only present when a test needs automation on more than one platform).",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": {
                  "started": [
                    {
                      "runId": "b1111111df174791a93e560390ea7e65"
                    }
                  ],
                  "queued": [
                    "ios"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "No build has been uploaded for this organisation (and no `bundleId` was given), so there is nothing to write the automation against."
          }
        }
      }
    },
    "/tests/folders": {
      "get": {
        "summary": "List folders",
        "description": "List the folders your tests are organised into. Each folder carries its full path (`Checkout / Payments`) and how many tests are in it, counting its subfolders, so one call is enough to find the folder you want. `unfiledTestCount` is how many tests are in no folder at all.",
        "operationId": "list_test_folders",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "folders": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Folder"
                      }
                    },
                    "unfiledTestCount": {
                      "type": "integer",
                      "description": "Tests that are in no folder."
                    }
                  }
                },
                "example": {
                  "folders": [
                    {
                      "id": "kFq2b8s1TzYwm0Xd4eNc",
                      "name": "Checkout",
                      "parentId": null,
                      "path": "Checkout",
                      "testCount": 12
                    },
                    {
                      "id": "p7Rw3nVa5LcQe1Zt9uHb",
                      "name": "Payments",
                      "parentId": "kFq2b8s1TzYwm0Xd4eNc",
                      "path": "Checkout / Payments",
                      "testCount": 4
                    }
                  ],
                  "unfiledTestCount": 3
                }
              }
            }
          },
          "400": {
            "description": "This organisation's tests are QA Studio no-code tests, which this API does not file into folders."
          }
        }
      },
      "post": {
        "summary": "Create folder",
        "description": "Create a folder. Pass `parentId` to nest it inside another folder, or leave it out for a top-level one. Folder names are for people to read: two folders may share a name, and everything that refers to a folder uses its id.",
        "operationId": "create_test_folder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFolder"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "folderId": {
                      "type": "string",
                      "description": "The unique identifier of the created folder."
                    },
                    "folder": {
                      "$ref": "#/components/schemas/Folder"
                    }
                  }
                },
                "example": {
                  "folderId": "p7Rw3nVa5LcQe1Zt9uHb",
                  "folder": {
                    "id": "p7Rw3nVa5LcQe1Zt9uHb",
                    "name": "Payments",
                    "parentId": "kFq2b8s1TzYwm0Xd4eNc",
                    "path": "Checkout / Payments",
                    "testCount": 0
                  }
                }
              }
            }
          },
          "400": {
            "description": "The name is empty or longer than 60 characters, or this organisation's tests are QA Studio no-code tests."
          },
          "404": {
            "description": "The folder named as `parentId` does not exist."
          }
        }
      },
      "patch": {
        "summary": "Rename or move folder",
        "description": "Rename a folder, move it under another folder, or both in one call. `parentId: null` moves it back to the top level; omitting `parentId` leaves it where it is. Moving a folder takes its subfolders and its tests with it. Both halves are applied together, so a refused move never leaves the rename it came with applied.",
        "operationId": "update_test_folder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFolder"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "message": "Folder renamed and moved successfully",
                  "folderId": "p7Rw3nVa5LcQe1Zt9uHb"
                }
              }
            }
          },
          "400": {
            "description": "Neither `name` nor `parentId` was given, the name is empty or too long, or the move would put the folder inside its own subtree."
          },
          "404": {
            "description": "The folder, or the folder named as `parentId`, does not exist."
          }
        }
      },
      "delete": {
        "summary": "Delete folder",
        "description": "Delete a folder. **No test is deleted**: the folder's subfolders move up to its own parent and its tests become unfiled, and the response says which. To delete the tests too, call `DELETE /tests` with their ids first.",
        "operationId": "delete_test_folder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteFolder"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "folderId": {
                      "type": "string"
                    },
                    "promotedFolderIds": {
                      "type": "array",
                      "description": "Subfolders that moved up to the deleted folder's parent.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "unfiledTestIds": {
                      "type": "array",
                      "description": "Tests that were in the folder and are now in no folder.",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": {
                  "message": "Folder 'Checkout' was deleted. 1 subfolder(s) moved up, 3 test(s) unfiled. No test was deleted.",
                  "folderId": "kFq2b8s1TzYwm0Xd4eNc",
                  "promotedFolderIds": [
                    "p7Rw3nVa5LcQe1Zt9uHb"
                  ],
                  "unfiledTestIds": [
                    "xMIt964RUpAB95b6YI2F"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No such folder in this organisation."
          }
        }
      }
    },
    "/tests/folders/move": {
      "post": {
        "summary": "Move tests into a folder",
        "description": "File several tests into a folder at once, or unfile them with `folderId: null`. Ids that no longer exist are skipped rather than failing the call, and a test already in that folder is left alone. To move a single test, `PATCH /tests` takes `folderId` too.",
        "operationId": "move_tests_to_folder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveTests"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "movedTestIds": {
                      "type": "array",
                      "description": "Tests that changed folder.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "unchangedTestIds": {
                      "type": "array",
                      "description": "Tests that were already in that folder.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "skippedTestIds": {
                      "type": "array",
                      "description": "Ids that do not belong to any test in this organisation.",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": {
                  "message": "Tests with following IDs were moved to 'kFq2b8s1TzYwm0Xd4eNc': ['xMIt964RUpAB95b6YI2F'].",
                  "movedTestIds": [
                    "xMIt964RUpAB95b6YI2F"
                  ],
                  "unchangedTestIds": [],
                  "skippedTestIds": []
                }
              }
            }
          },
          "404": {
            "description": "The destination folder does not exist, or none of the ids match a test in this organisation."
          }
        }
      }
    },
    "/uploadBuild": {
      "post": {
        "summary": "Upload build",
        "description": "Upload an application build artifact (.apk for Android, .zip/.tar.gz for iOS) to use in test executions.",
        "operationId": "upload_build",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/UploadBuild"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "buildId": {
                      "type": "string",
                      "description": "The unique identifier for the uploaded build."
                    },
                    "app_link": {
                      "type": "string",
                      "description": "A direct link to the uploaded build in the MobileBoost dashboard."
                    }
                  },
                  "required": [
                    "buildId",
                    "app_link"
                  ]
                },
                "example": {
                  "buildId": "abc123def456",
                  "app_link": "https://app.mobileboost.io/gpt-driver/build/abc123def456"
                }
              }
            }
          }
        }
      }
    },
    "/builds/{upload_id}": {
      "delete": {
        "summary": "Delete build",
        "description": "Delete a previously uploaded build by its ID.",
        "operationId": "delete_build",
        "parameters": [
          {
            "required": true,
            "schema": {
              "title": "Upload ID",
              "type": "string"
            },
            "name": "upload_id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/runs": {
      "get": {
        "summary": "Get runs",
        "description": "Retrieve test runs for your organisation. Returns the most recent runs, up to the specified limit.",
        "operationId": "get_runs",
        "parameters": [
          {
            "required": true,
            "schema": {
              "title": "Organisation ID",
              "type": "string"
            },
            "name": "organisationId",
            "in": "query"
          },
          {
            "required": false,
            "schema": {
              "title": "Limit",
              "type": "integer",
              "default": 20
            },
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/runs/{run_id}": {
      "get": {
        "summary": "Get run status",
        "description": "Retrieve the status and per-test results for a specific run. Each result entry contains the test ID, title, status, a link to the recording, and a link to the per-step interaction logs.",
        "operationId": "get_run_status",
        "parameters": [
          {
            "required": true,
            "schema": {
              "title": "Run ID",
              "type": "string"
            },
            "name": "run_id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runId": {
                      "type": "string",
                      "description": "The ID of the run."
                    },
                    "status": {
                      "type": "string",
                      "description": "Overall status of the run (e.g. `pending`, `running`, `completed`)."
                    },
                    "totalTests": {
                      "type": "integer",
                      "description": "Total number of tests in the run."
                    },
                    "succeededTests": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TestRunResult"
                      },
                      "description": "Tests that succeeded."
                    },
                    "failedTests": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TestRunResult"
                      },
                      "description": "Tests that failed."
                    },
                    "blockedTests": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TestRunResult"
                      },
                      "description": "Tests that were blocked."
                    }
                  }
                },
                "example": {
                  "runId": "abc123",
                  "status": "completed",
                  "totalTests": 2,
                  "succeededTests": [
                    {
                      "id": "test1",
                      "title": "Login flow",
                      "status": "succeeded",
                      "recording": "https://app.mobileboost.io/recording/abc123/runs/test1",
                      "interactionLogs": "https://api.mobileboost.io/suite/abc123/run/test1/interaction_logs?organisation_id=org123"
                    }
                  ],
                  "failedTests": [
                    {
                      "id": "test2",
                      "title": "Checkout flow",
                      "status": "failed",
                      "recording": "https://app.mobileboost.io/recording/abc123/runs/test2",
                      "interactionLogs": "https://api.mobileboost.io/suite/abc123/run/test2/interaction_logs?organisation_id=org123"
                    }
                  ],
                  "blockedTests": []
                }
              }
            }
          }
        }
      }
    },
    "/audit/logs": {
      "get": {
        "summary": "List audit logs",
        "description": "Retrieve your organisation\u2019s audit log events as a paginated, cursor-based stream. This endpoint is intended for SIEM ingestion, such as a Splunk REST or modular input. Poll with `since=<next_cursor>` from the previous response to fetch only new events.\n\nAudit logging must be enabled for your organisation. If audit logging is not enabled, the endpoint returns `403`. The organisation is derived from the API key which can be created in your organisations account.\n\nSet the `Accept` header to `application/x-ndjson` to receive newline-delimited JSON instead of a single JSON object. In this mode, the next cursor is returned in the `X-Next-Cursor` response header rather than in a response field.",
        "operationId": "get_audit_logs",
        "parameters": [
          {
            "required": false,
            "schema": {
              "title": "Since",
              "type": "string"
            },
            "name": "since",
            "in": "query",
            "description": "Cursor: the `next_cursor` value from the previous response. Omit to start from the beginning of the retained log."
          },
          {
            "required": false,
            "schema": {
              "title": "Limit",
              "type": "integer",
              "default": 100,
              "minimum": 1,
              "maximum": 1000
            },
            "name": "limit",
            "in": "query",
            "description": "Maximum number of events to return (1-1000)."
          },
          {
            "required": false,
            "schema": {
              "title": "Event Type",
              "type": "string"
            },
            "name": "event_type",
            "in": "query",
            "description": "Exact match on `event_type` (e.g. `test.updated`, `login.succeeded`)."
          },
          {
            "required": false,
            "schema": {
              "title": "From",
              "type": "string",
              "format": "date-time",
              "example": "2026-06-01T00:00:00Z"
            },
            "name": "from",
            "in": "query",
            "description": "ISO-8601 lower bound (inclusive) on `created_at`."
          },
          {
            "required": false,
            "schema": {
              "title": "To",
              "type": "string",
              "format": "date-time"
            },
            "name": "to",
            "in": "query",
            "description": "ISO-8601 upper bound (inclusive) on `created_at`."
          },
          {
            "required": false,
            "schema": {
              "title": "Actor",
              "type": "string"
            },
            "name": "actor",
            "in": "query",
            "description": "Substring match against the acting user's `uid` or `email`."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "logs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditLogEntry"
                      },
                      "description": "Audit events, ordered oldest to newest."
                    },
                    "next_cursor": {
                      "type": "string",
                      "nullable": true,
                      "description": "Pass as `since` to fetch the next page. `null` when the current page wasn't full (no more events yet)."
                    }
                  }
                },
                "example": {
                  "logs": [
                    {
                      "seq": "2026-06-26T12:00:00.000000+00:00#aB3xY",
                      "timestamp": "2026-06-26T12:00:00.000Z",
                      "created_at": "2026-06-26T12:00:00.000000+00:00",
                      "org_id": "org_abc",
                      "event_type": "test.updated",
                      "action": "update",
                      "actor": {
                        "uid": "u_123",
                        "email": "jane@example.com"
                      },
                      "target": {
                        "type": "test",
                        "id": "abc123",
                        "name": "Login flow"
                      },
                      "changes": [
                        {
                          "field": "commands",
                          "old": "Tap Log in",
                          "new": "Tap Sign in"
                        }
                      ],
                      "source": "backend",
                      "metadata": {}
                    }
                  ],
                  "next_cursor": "2026-06-26T12:00:00.000000+00:00#aB3xY"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "string",
                  "description": "Newline-delimited JSON \u2014 one AuditLogEntry object per line. The next cursor is returned via the `X-Next-Cursor` response header instead of an in-body field."
                }
              }
            }
          },
          "403": {
            "description": "Audit logging is not enabled for this organisation, or the API key's scope isn't permitted to call this endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "audit logging is not enabled for this organisation"
                }
              }
            }
          }
        }
      }
    },
    "/suite/{suite_id}/status": {
      "get": {
        "summary": "Get suite status",
        "description": "Retrieve the results and status of a specific test suite run.",
        "operationId": "get_suite_status",
        "parameters": [
          {
            "required": true,
            "schema": {
              "title": "Suite ID",
              "type": "string"
            },
            "name": "suite_id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Create": {
        "title": "Create",
        "required": [
          "commands"
        ],
        "type": "object",
        "properties": {
          "commands": {
            "title": "Commands",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Natural-language commands that make up the test case."
          },
          "autoGenerate": {
            "title": "Auto-generate",
            "type": "boolean",
            "default": true,
            "description": "Whether creating this test should automatically trigger MobileBoost to write and verify its automation code. Defaults to true; pass false to skip automatic generation."
          },
          "title": {
            "title": "Title",
            "type": "string",
            "default": "",
            "description": "Human-readable title of the test."
          },
          "tags": {
            "title": "Tags",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags used to group or filter tests."
          },
          "preRequests": {
            "title": "Pre-requests",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PreRequest"
            },
            "description": "HTTP requests executed before the test runs (e.g. to seed state or fetch tokens)."
          },
          "launchParams": {
            "title": "Launch parameters",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LaunchParam"
            },
            "description": "Key/value pairs passed to the test at launch."
          },
          "testInputs": {
            "title": "Test inputs",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestInput"
            },
            "description": "Named inputs referenced by the test commands, with default values."
          },
          "teardownRequests": {
            "title": "Teardown requests",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TearDownRequest"
            },
            "description": "HTTP requests executed after the test finishes (e.g. to clean up state)."
          },
          "folderId": {
            "title": "Folder ID",
            "type": "string",
            "description": "File the new test into this folder. Omit it and the test is unfiled. `GET /tests/folders` has the ids."
          }
        }
      },
      "PreRequest": {
        "title": "PreRequest",
        "type": "object",
        "properties": {
          "curlCommand": {
            "title": "cURL command",
            "type": "string",
            "default": "",
            "description": "The cURL command to execute before the test runs."
          },
          "delayBeforeRequest": {
            "title": "Delay before request",
            "type": "integer",
            "default": 0,
            "description": "Delay in milliseconds to wait before issuing the request."
          },
          "valuesToRemember": {
            "title": "Values to remember",
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": [],
            "description": "JSON paths (or identifiers) of values from the response to remember for later use in the test."
          }
        }
      },
      "TearDownRequest": {
        "title": "TearDownRequest",
        "type": "object",
        "properties": {
          "curlCommand": {
            "title": "cURL command",
            "type": "string",
            "default": "",
            "description": "The cURL command to execute after the test finishes."
          }
        }
      },
      "LaunchParam": {
        "title": "LaunchParam",
        "required": [
          "key",
          "value"
        ],
        "type": "object",
        "properties": {
          "key": {
            "title": "Key",
            "type": "string",
            "description": "Launch parameter name."
          },
          "value": {
            "title": "Value",
            "type": "string",
            "description": "Launch parameter value."
          }
        }
      },
      "TestInput": {
        "title": "TestInput",
        "required": [
          "key",
          "defaultValue"
        ],
        "type": "object",
        "properties": {
          "key": {
            "title": "Key",
            "type": "string",
            "description": "Input identifier referenced by the test commands."
          },
          "defaultValue": {
            "title": "Default value",
            "type": "string",
            "description": "Default value used when no override is supplied at execution time."
          }
        }
      },
      "Update": {
        "title": "Update",
        "description": "Send `testId` plus at least one field to change. An omitted field is left as it is.",
        "required": [
          "testId"
        ],
        "type": "object",
        "properties": {
          "testId": {
            "title": "Test ID",
            "type": "string"
          },
          "commands": {
            "title": "Commands",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "autoGenerate": {
            "title": "Auto-generate",
            "type": "boolean",
            "default": true,
            "description": "Whether updating this test's commands should automatically re-trigger MobileBoost to write and verify its automation code. Defaults to true; pass false to skip automatic generation."
          },
          "folderId": {
            "title": "Folder ID",
            "type": "string",
            "nullable": true,
            "description": "Move the test to this folder, or `null` to take it out of its folder. Omit the field to leave the folder as it is. Changing a test's folder never re-triggers automation generation: it does not change what the test should do."
          }
        }
      },
      "Delete": {
        "title": "Delete",
        "type": "object",
        "properties": {
          "testId": {
            "title": "Test ID",
            "type": "string"
          },
          "testIds": {
            "title": "Test IDs",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ExecuteTest": {
        "title": "ExecuteTest",
        "required": [
          "organisationid"
        ],
        "type": "object",
        "properties": {
          "organisationid": {
            "title": "Organisation ID",
            "type": "string",
            "description": "Your MobileBoost organisation ID."
          },
          "buildid": {
            "title": "Build ID",
            "type": "string",
            "description": "Alternative build identifier."
          },
          "platform": {
            "title": "Platform",
            "type": "string",
            "description": "Target platform (e.g. `ios`, `android`)."
          },
          "testids": {
            "title": "Test IDs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of existing test cases to execute."
          },
          "tags": {
            "title": "Tags",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Execute all tests matching these tags."
          },
          "tagsquery": {
            "title": "Tags query",
            "type": "string",
            "description": "A query expression to match tests by tags."
          },
          "iterations": {
            "title": "Iterations",
            "type": "integer",
            "description": "Number of times to repeat the test execution."
          },
          "launchparams": {
            "title": "Launch parameters",
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Key-value pairs passed to the app at launch."
          },
          "deviceprovidersettings": {
            "title": "Device provider settings",
            "type": "object",
            "description": "Provider-specific device configuration."
          },
          "build": {
            "$ref": "#/components/schemas/Build"
          },
          "testinputs": {
            "title": "Test inputs",
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              }
            },
            "description": "Per-test input overrides, keyed by test ID."
          },
          "deviceconfigs": {
            "title": "Device configs",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceConfiguration"
            },
            "default": [],
            "description": "List of device configurations to run tests on."
          },
          "metadata": {
            "title": "Metadata",
            "type": "object",
            "default": {},
            "description": "Arbitrary metadata to attach to the execution."
          }
        }
      },
      "GenerateTests": {
        "title": "GenerateTests",
        "required": [
          "organisationId",
          "testIds"
        ],
        "type": "object",
        "properties": {
          "organisationId": {
            "title": "Organisation ID",
            "type": "string",
            "description": "Your MobileBoost organisation ID."
          },
          "testIds": {
            "title": "Test IDs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of existing test cases to write automation for. Each test must already have a description, since generation writes code for the described behaviour rather than inventing one."
          },
          "uploadId": {
            "title": "Upload ID",
            "type": "string",
            "description": "Write the automation against a specific uploaded build instead of the organisation's newest one."
          },
          "bundleId": {
            "title": "Bundle ID",
            "type": "string",
            "description": "Write the automation against the app already installed on your reserved device, instead of an uploaded build. May omit `platform`, which is then taken from the reserved device."
          },
          "platform": {
            "title": "Platform",
            "type": "string",
            "description": "Restrict generation to one platform (`ios` or `android`). Taken from the upload when omitted with `uploadId`; with neither `uploadId` nor `bundleId`, omitting this generates against every platform the organisation has a build for."
          },
          "testsRepo": {
            "title": "Tests repo",
            "type": "string",
            "description": "Override the organisation's managed test repository. Normally left unset, since generation resolves the repo automatically and creates one if the organisation doesn't have one yet."
          },
          "usePhysicalDevice": {
            "title": "Use physical device",
            "type": "boolean",
            "description": "Run the generation on a physical device instead of a simulator/emulator. Forced on automatically for iOS `.ipa` builds and for bundle-only (buildless) generation."
          },
          "verificationRounds": {
            "title": "Verification rounds",
            "type": "integer",
            "description": "How many consecutive passing runs the generated test must produce before it is committed. Defaults to 3. Raising this increases confidence at the cost of one full test run per extra round."
          },
          "tunnelName": {
            "title": "Tunnel name",
            "type": "string",
            "description": "Name of the tunnel to route the device through, for apps whose flow touches an internal/non-public host."
          }
        }
      },
      "Folder": {
        "title": "Folder",
        "type": "object",
        "properties": {
          "id": {
            "title": "Folder ID",
            "type": "string",
            "description": "The id everything else refers to this folder by."
          },
          "name": {
            "title": "Name",
            "type": "string",
            "description": "Display name. Two folders may share one."
          },
          "parentId": {
            "title": "Parent ID",
            "type": "string",
            "nullable": true,
            "description": "The folder this one sits in, or `null` at the top level."
          },
          "path": {
            "title": "Path",
            "type": "string",
            "description": "The names from the top level down, joined with ` / `."
          },
          "testCount": {
            "title": "Test count",
            "type": "integer",
            "description": "Tests in this folder, counting its subfolders."
          }
        }
      },
      "CreateFolder": {
        "title": "CreateFolder",
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "title": "Name",
            "type": "string",
            "maxLength": 60,
            "description": "Display name, up to 60 characters."
          },
          "parentId": {
            "title": "Parent ID",
            "type": "string",
            "nullable": true,
            "description": "Nest the new folder inside this one. Omit it, or send `null`, for a top-level folder."
          }
        }
      },
      "UpdateFolder": {
        "title": "UpdateFolder",
        "description": "Send `folderId` plus `name`, `parentId`, or both.",
        "required": [
          "folderId"
        ],
        "type": "object",
        "properties": {
          "folderId": {
            "title": "Folder ID",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string",
            "maxLength": 60,
            "description": "The new display name. Omit it to leave the name as it is."
          },
          "parentId": {
            "title": "Parent ID",
            "type": "string",
            "nullable": true,
            "description": "Move the folder under this one, or `null` to move it to the top level. Omit the field to leave it where it is. A folder cannot be moved inside itself or one of its own subfolders."
          }
        }
      },
      "DeleteFolder": {
        "title": "DeleteFolder",
        "required": [
          "folderId"
        ],
        "type": "object",
        "properties": {
          "folderId": {
            "title": "Folder ID",
            "type": "string"
          }
        }
      },
      "MoveTests": {
        "title": "MoveTests",
        "required": [
          "testIds"
        ],
        "type": "object",
        "properties": {
          "testIds": {
            "title": "Test IDs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The tests to file. Ids that no longer exist are skipped and reported back."
          },
          "folderId": {
            "title": "Folder ID",
            "type": "string",
            "nullable": true,
            "description": "The destination folder, or `null` to take the tests out of their folders."
          }
        }
      },
      "Build": {
        "title": "Build",
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/BuildMeta"
          }
        }
      },
      "BuildMeta": {
        "title": "BuildMeta",
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "title": "Name",
            "type": "string"
          }
        }
      },
      "DeviceConfiguration": {
        "title": "DeviceConfiguration",
        "type": "object",
        "properties": {
          "locale": {
            "title": "Locale",
            "type": "string",
            "default": ""
          },
          "organizationid": {
            "title": "Organisation ID",
            "type": "string",
            "default": ""
          },
          "osversion": {
            "title": "OS version",
            "type": "string",
            "default": ""
          },
          "platform": {
            "title": "Platform",
            "type": "string",
            "default": ""
          },
          "device": {
            "title": "Device",
            "type": "string",
            "default": ""
          },
          "orientation": {
            "title": "Orientation",
            "type": "string",
            "default": ""
          },
          "coordinates": {
            "title": "Coordinates",
            "type": "object",
            "default": {}
          }
        }
      },
      "TestRunResult": {
        "title": "TestRunResult",
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The test run ID."
          },
          "title": {
            "type": "string",
            "description": "The test title."
          },
          "status": {
            "type": "string",
            "description": "The test result status (`succeeded`, `failed`, or `blocked`)."
          },
          "recording": {
            "type": "string",
            "description": "URL to the test's recording in the MobileBoost dashboard."
          },
          "interactionLogs": {
            "type": "string",
            "description": "URL to the per-step interaction logs for this test run."
          }
        }
      },
      "UploadBuild": {
        "title": "UploadBuild",
        "required": [
          "build",
          "organisation_key",
          "platform"
        ],
        "type": "object",
        "properties": {
          "build": {
            "title": "Build",
            "type": "string",
            "format": "binary",
            "description": "The build file (.apk for Android, .zip/.tar.gz for iOS)."
          },
          "organisation_key": {
            "title": "Organisation key",
            "type": "string",
            "description": "Your MobileBoost organisation key."
          },
          "platform": {
            "title": "Platform",
            "type": "string",
            "description": "Target platform (`android` or `ios`)."
          },
          "metadata": {
            "title": "Metadata",
            "type": "string",
            "description": "Optional JSON metadata string."
          }
        }
      },
      "AuditLogEntry": {
        "type": "object",
        "description": "A single canonical audit event.",
        "properties": {
          "seq": {
            "type": "string",
            "description": "Monotonic ordering key (`created_at` + a doc-id tiebreak). Use this as the `since` cursor."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the audited event occurred (defaults to `created_at` if not supplied by the producer)."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the audit record was written; the field `from`/`to` filter against."
          },
          "org_id": {
            "type": "string",
            "description": "Your organisation ID (always matches the API key's organisation)."
          },
          "event_type": {
            "type": "string",
            "description": "Dotted event taxonomy, e.g. `test.updated`, `login.succeeded`, `member.role_changed`, `api_key.created`."
          },
          "action": {
            "type": "string",
            "description": "One of `create`, `update`, `delete`, `login`."
          },
          "actor": {
            "type": "object",
            "description": "Who performed the action. System-originated writes use a `uid` like `api:uploadBuild` or `webhook:githubApp`.",
            "properties": {
              "uid": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "nullable": true
              },
              "ip": {
                "type": "string",
                "nullable": true
              },
              "user_agent": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "target": {
            "type": "object",
            "description": "What was acted on.",
            "properties": {
              "type": {
                "type": "string"
              },
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "changes": {
            "type": "array",
            "description": "Field-level diffs for update events (empty for pure events like logins). Sensitive fields are recorded as a salted hash (`{\"masked\": true, \"hash\": \"...\"}`) instead of plaintext.",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "old": {},
                "new": {}
              }
            }
          },
          "source": {
            "type": "string",
            "description": "Producer of the event: `cloud_function`, `backend`, or `client_reported`."
          },
          "metadata": {
            "type": "object",
            "description": "Additional event-specific context."
          }
        }
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    }
  }
}
