{"info":{"title":"TestingBot REST API","description":"Programmatic access to TestingBot test runs, builds, tunnels, devices, storage, Codeless tests, and team management. Authentication uses HTTP Basic with your API key and secret.","termsOfService":"https://testingbot.com/terms-of-service","contact":{"name":"TestingBot Support","email":"info@testingbot.com","url":"https://testingbot.com/contact"},"version":"0.0.1"},"swagger":"2.0","produces":["application/json"],"host":"api.testingbot.com","basePath":"/api","tags":[{"name":"Devices","description":"Operations about Devices"},{"name":"Configuration","description":"Operations about Configurations"},{"name":"Browsers","description":"Operations about Browsers"},{"name":"Tunnel","description":"Operations about Tunnels"},{"name":"Jobs","description":"Operations about Jobs"},{"name":"Team","description":"Operations about Teams"},{"name":"Storage","description":"Operations about Storages"},{"name":"Screenshots","description":"Operations about Screenshots"},{"name":"Codeless suites","description":"Operations about Codeless suites"},{"name":"Codeless tests","description":"Operations about Codeless tests"},{"name":"Builds","description":"Operations about Builds"},{"name":"Tests","description":"Operations about Tests"},{"name":"User","description":"Operations about Users"}],"paths":{"/v1/devices":{"get":{"summary":"List physical mobile devices","description":"Returns every real Android and iOS device in the TestingBot grid, with an `available` flag indicating whether it can be acquired right now. Filter by `platform` for a single OS family.","produces":["application/json"],"parameters":[{"in":"query","name":"platform","description":"Filter to a single mobile OS family. Case-insensitive.","type":"string","enum":["Android","iOS","REAL_ANDROID","REAL_IOS"],"required":false},{"in":"query","name":"web","description":"Internal flag used by the dashboard — returns extra UI-only fields.","type":"boolean","required":false}],"responses":{"200":{"description":"List physical mobile devices","schema":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Device"}}}},"tags":["Devices"],"operationId":"getV1Devices"}},"/v1/devices/available":{"get":{"summary":"List currently available devices","description":"Subset of /v1/devices filtered to devices the authenticated account can acquire right now (not in use by another customer, not under maintenance).","produces":["application/json"],"responses":{"200":{"description":"List currently available devices","schema":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Device"}}}},"tags":["Devices"],"operationId":"getV1DevicesAvailable"}},"/v1/devices/{id}":{"get":{"summary":"Get a specific device","description":"Returns the spec and current availability for a single device by numeric ID.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric device ID.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a specific device","schema":{"$ref":"#/definitions/Testingbot_Entities_Device"}},"401":{"description":"Authentication required"},"404":{"description":"Device not found"}},"tags":["Devices"],"operationId":"getV1DevicesId"}},"/v1/configuration/ip-ranges":{"get":{"summary":"TestingBot IP ranges for firewall whitelisting","description":"Returns the up-to-date list of public IPv4 addresses used by TestingBot test machines. Allow these in your firewall when running tests against staging or production behind corporate VPN/network rules. The response is a flat JSON array of IPv4 strings (no CIDR ranges, no metadata) — re-fetch periodically since the pool changes as we scale capacity. Unauthenticated; no `key`/`secret` required.","produces":["application/json"],"responses":{"200":{"description":"TestingBot IP ranges for firewall whitelisting"}},"tags":["Configuration"],"operationId":"getV1ConfigurationIpRanges"}},"/v1/browsers":{"get":{"summary":"List supported browsers","description":"Returns every browser environment available on the TestingBot grid: name, version, platform, and the `browser_id` used when attaching browsers to Codeless tests. No authentication required.","produces":["application/json"],"parameters":[{"in":"query","name":"type","description":"Filter by automation protocol: \"webdriver\" (default) or \"rc\" (legacy Selenium RC).","type":"string","enum":["webdriver","rc"],"required":false}],"responses":{"200":{"description":"List supported browsers","schema":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Browser"}}}},"tags":["Browsers"],"operationId":"getV1Browsers"}},"/v1/tunnel/list":{"get":{"summary":"List active tunnels","description":"Returns every TestingBot Tunnel currently running under the account. Use this to monitor running tunnels in CI dashboards or to find a tunnel ID before tearing it down.","produces":["application/json"],"responses":{"200":{"description":"List active tunnels","schema":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Tunnel"}}},"401":{"description":"Authentication required"}},"tags":["Tunnel"],"operationId":"getV1TunnelList"}},"/v1/tunnel/isalive-check":{"get":{"summary":"Liveness check","description":"Unauthenticated ping endpoint used by the tunnel binary itself to confirm it can reach the TestingBot API. Always returns `{ success: true }`.","produces":["application/json"],"responses":{"200":{"description":"Liveness check","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}}},"tags":["Tunnel"],"operationId":"getV1TunnelIsaliveCheck"}},"/v1/tunnel/{id}":{"get":{"summary":"Get a specific tunnel","description":"Returns the current state of a tunnel by ID. Returns 500 with the underlying error if the tunnel is in a transition state or no longer exists.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric tunnel ID returned by /v1/tunnel/list or /v1/tunnel/create.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a specific tunnel","schema":{"$ref":"#/definitions/Testingbot_Entities_Tunnel"}},"401":{"description":"Authentication required"}},"tags":["Tunnel"],"operationId":"getV1TunnelId"},"delete":{"summary":"Stop a tunnel","description":"Tears down a running tunnel. Use this in CI teardown steps to release the slot for the next run; idle tunnels also self-terminate after the configured timeout.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric tunnel ID to stop.","type":"integer","format":"int32","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Stop a tunnel","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"}},"tags":["Tunnel"],"operationId":"deleteV1TunnelId"}},"/v1/tunnel":{"get":{"summary":"Get the user's active tunnel","description":"Returns the first active tunnel for the authenticated account (regardless of ID). Convenience endpoint when you only run one tunnel at a time.","produces":["application/json"],"responses":{"200":{"description":"Get the user's active tunnel","schema":{"$ref":"#/definitions/Testingbot_Entities_Tunnel"}},"401":{"description":"Authentication required"}},"tags":["Tunnel"],"operationId":"getV1Tunnel"},"delete":{"summary":"Stop the user's active tunnel","description":"Tears down whichever tunnel is currently active on the account, without needing to specify an ID. Useful when you only ever run one tunnel and want a simple cleanup call.","produces":["application/json"],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Stop the user's active tunnel","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"}},"tags":["Tunnel"],"operationId":"deleteV1Tunnel"}},"/v1/tunnel/create":{"post":{"summary":"Create a tunnel","description":"Launches a new TestingBot Tunnel VM and returns its connection metadata. Most users start tunnels via the tunnel client/CLI rather than this endpoint directly.","produces":["application/json"],"consumes":["application/json"],"responses":{"201":{"description":"Create a tunnel","schema":{"$ref":"#/definitions/Testingbot_Entities_Tunnel"}},"401":{"description":"Authentication required"},"402":{"description":"Tunnel quota exhausted"}},"tags":["Tunnel"],"operationId":"postV1TunnelCreate"}},"/v1/jobs/{id}":{"get":{"summary":"Get a job's status","description":"Returns the live status of an asynchronous job — typically used to poll Codeless test/suite runs started by `POST /v1/lab/:id/trigger`, `POST /v1/lab/trigger_all`, or `POST /v1/labsuites/:id/trigger`. Once `status` is FINISHED, the response includes `success` and per-test results.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric job ID returned by a trigger endpoint.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a job's status","schema":{"$ref":"#/definitions/Testingbot_Entities_Job"}},"401":{"description":"Authentication required"},"404":{"description":"Job not found"}},"tags":["Jobs"],"operationId":"getV1JobsId"}},"/v1/team-management":{"get":{"summary":"Get team concurrency info","description":"Returns allowed vs current concurrent session counts for the team across both VMs and physical mobile devices. Useful for dashboards that surface \"X of Y slots in use\".","produces":["application/json"],"responses":{"200":{"description":"Get team concurrency info","schema":{"$ref":"#/definitions/Testingbot_Entities_Team"}},"401":{"description":"Authentication required"}},"tags":["Team"],"operationId":"getV1TeamManagement"}},"/v1/team-management/users":{"get":{"summary":"List users in your team","description":"Paginated list of all sub-accounts in the team. Requires admin role on the calling account.","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many users from the start of the result set.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of users to return (max 500).","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List users in your team","schema":{"$ref":"#/definitions/Testingbot_Entities_TeamMemberList"}},"401":{"description":"Authentication required"},"403":{"description":"Caller is not a team admin"}},"tags":["Team"],"operationId":"getV1TeamManagementUsers"},"post":{"summary":"Create a user in your team","description":"Provisions a new sub-account inside the team, copying the caller's subscription level and assigning a slice of the credit pool. Requires an upgraded plan and admin role.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1TeamManagementUsers","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1TeamManagementUsers"}}],"responses":{"201":{"description":"Create a user in your team","schema":{"$ref":"#/definitions/Testingbot_Entities_TeamMember"}},"401":{"description":"Authentication required"},"403":{"description":"Caller is not on a paid plan / not admin"}},"tags":["Team"],"operationId":"postV1TeamManagementUsers"}},"/v1/team-management/users/{id}":{"get":{"summary":"Get a specific team user","description":"Returns the user record for a specific team member. Admins can fetch any team member; non-admins can only fetch themselves.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric ID of the team user to fetch.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a specific team user","schema":{"$ref":"#/definitions/Testingbot_Entities_TeamMember"}},"401":{"description":"Authentication required"},"403":{"description":"Not allowed"},"404":{"description":"User not found"}},"tags":["Team"],"operationId":"getV1TeamManagementUsersId"},"put":{"summary":"Update a user in your team","description":"Updates a team user's profile and credit allocation. Credit fields cannot exceed the team owner's remaining balance.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric ID of the team user to update.","type":"integer","format":"int32","required":true},{"name":"putV1TeamManagementUsersId","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1TeamManagementUsersId"}}],"responses":{"200":{"description":"Update a user in your team","schema":{"$ref":"#/definitions/Testingbot_Entities_TeamMember"}},"401":{"description":"Authentication required"},"403":{"description":"Caller is not on a paid plan / not admin / over allocation"},"404":{"description":"User not found"}},"tags":["Team"],"operationId":"putV1TeamManagementUsersId"}},"/v1/team-management/users/{id}/client-key":{"get":{"summary":"Get a team user's client key","description":"Admin-only endpoint that returns the API client key for a specific team user. Used by tooling that impersonates team members in CI; the secret is not exposed here — use reset-keys to rotate.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric ID of the team user whose key to fetch.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a team user's client key"},"401":{"description":"Authentication required"},"403":{"description":"Caller is not a team admin"},"404":{"description":"User not found"}},"tags":["Team"],"operationId":"getV1TeamManagementUsersIdClientKey"}},"/v1/team-management/users/{id}/reset-keys":{"post":{"summary":"Reset credentials for a team user","description":"Rotates both the API key and secret for a team user. The old credentials stop working immediately, so any deployed automation using them must be updated.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric ID of the team user whose credentials to rotate.","type":"integer","format":"int32","required":true}],"responses":{"201":{"description":"Reset credentials for a team user","schema":{"$ref":"#/definitions/Testingbot_Entities_TeamCredentialReset"}},"401":{"description":"Authentication required"},"403":{"description":"Caller is not admin / not the target user"},"404":{"description":"User not found"}},"tags":["Team"],"operationId":"postV1TeamManagementUsersIdResetKeys"}},"/v1/storage":{"post":{"summary":"Upload an app to storage","description":"Uploads an APK or IPA to TestingBot storage. Either send the binary as multipart `file` or pass a public `url` that TestingBot will fetch. The returned `app_url` (`tb://<appkey>`) can be set as the `app` capability on subsequent mobile sessions.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1Storage","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1Storage"}}],"responses":{"201":{"description":"Upload an app to storage","schema":{"$ref":"#/definitions/Testingbot_Entities_StorageFile"}},"400":{"description":"Missing file or url"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"}},"tags":["Storage"],"operationId":"postV1Storage"},"get":{"summary":"List your storage apps","description":"Paginated list of every app you've uploaded to TestingBot storage, newest first.","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many apps from the start of the result set.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of apps to return (max 500).","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List your storage apps","schema":{"$ref":"#/definitions/Testingbot_Entities_StorageFileList"}},"401":{"description":"Authentication required"}},"tags":["Storage"],"operationId":"getV1Storage"}},"/v1/storage/*":{"post":{"summary":"Update an app binary by appkey","description":"Replaces the binary stored under an existing `appkey`. The `app_url` (`tb://<appkey>`) stays the same so deployed CI configurations keep working without changes — useful for \"always use the latest\" CI flows.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1Storage*","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1Storage*"}}],"responses":{"201":{"description":"Update an app binary by appkey","schema":{"$ref":"#/definitions/Testingbot_Entities_StorageFile"}},"400":{"description":"Missing or invalid file/url"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"}},"tags":["Storage"],"operationId":"postV1Storage*"},"get":{"summary":"Get a stored app by appkey","description":"Returns metadata for a single uploaded app — its filename, type, version, icon, and download URL.","produces":["application/json"],"parameters":[{"in":"query","name":"splat","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a stored app by appkey","schema":{"$ref":"#/definitions/Testingbot_Entities_StorageFile"}},"401":{"description":"Authentication required"},"404":{"description":"App not found"}},"tags":["Storage"],"operationId":"getV1Storage*"}},"/v1/storage/{id}":{"delete":{"summary":"Delete a stored app","description":"Permanently removes the binary and its metadata. Sessions referencing the `app_url` after deletion will fail at session-start with \"app not found\".","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric storage ID or appkey to delete.","type":"string","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Delete a stored app","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"},"404":{"description":"App not found"}},"tags":["Storage"],"operationId":"deleteV1StorageId"}},"/v1/screenshots":{"get":{"summary":"List screenshot batches","description":"Returns batches of cross-browser screenshots the account has queued historically.","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many batches.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of batches to return.","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List screenshot batches","schema":{"$ref":"#/definitions/Testingbot_Entities_ScreenshotList"}},"401":{"description":"Authentication required"}},"tags":["Screenshots"],"operationId":"getV1Screenshots"},"post":{"summary":"Capture a new screenshot batch","description":"Queues a cross-browser screenshot of a given URL at a specified resolution. Returns a batch ID you can poll via GET /v1/screenshots/:id.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1Screenshots","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1Screenshots"}}],"responses":{"201":{"description":"Capture a new screenshot batch","schema":{"$ref":"#/definitions/Testingbot_Entities_Screenshot"}},"400":{"description":"Missing required parameters"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"}},"tags":["Screenshots"],"operationId":"postV1Screenshots"}},"/v1/screenshots/{id}":{"get":{"summary":"Get screenshot batch detail","description":"Returns per-browser screenshot results for a single batch, including thumbnail/image URLs and processing state.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric screenshot batch ID.","type":"integer","format":"int32","required":true},{"in":"query","name":"excludeIds","description":"Comma-separated screenshot IDs to exclude (useful for delta-fetch).","type":"string","required":false}],"responses":{"200":{"description":"Get screenshot batch detail","schema":{"$ref":"#/definitions/Testingbot_Entities_Screenshot"}},"401":{"description":"Authentication required"},"404":{"description":"Batch not found"}},"tags":["Screenshots"],"operationId":"getV1ScreenshotsId"}},"/v1/labsuites":{"get":{"summary":"List your Codeless suites","description":"Paginated list of every Codeless suite (a.k.a. Lab suite) on the account. A suite groups several Codeless tests so they can be scheduled, triggered, and reported on as a unit.","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many suites from the start of the result set.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of suites to return (max 500).","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List your Codeless suites","schema":{"$ref":"#/definitions/Testingbot_Entities_LabSuiteList"}},"401":{"description":"Authentication required"}},"tags":["Codeless suites"],"operationId":"getV1Labsuites"},"post":{"summary":"Create a Codeless suite","description":"Creates a new Codeless suite. Attach Codeless tests with `POST /v1/labsuites/:id/tests` after creation.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1Labsuites","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1Labsuites"}}],"responses":{"201":{"description":"Create a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_LabSuiteCreateAck"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"}},"tags":["Codeless suites"],"operationId":"postV1Labsuites"}},"/v1/labsuites/{id}/trigger":{"post":{"summary":"Run a Codeless suite","description":"Queues every test in the suite for an immediate run. Returns a job_id you can poll with `GET /v1/jobs/:id`.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID to trigger.","type":"integer","format":"int32","required":true}],"responses":{"201":{"description":"Run a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_LabRunAck"}},"401":{"description":"Authentication required"},"402":{"description":"Insufficient credits"},"403":{"description":"Account is read-only"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"postV1LabsuitesIdTrigger"}},"/v1/labsuites/{id}":{"get":{"summary":"Get a specific Codeless suite","description":"Returns a single Codeless suite's configuration: schedule, alerts, attached browsers, and number of tests inside.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a specific Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_LabSuite"}},"401":{"description":"Authentication required"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"getV1LabsuitesId"},"delete":{"summary":"Delete a Codeless suite","description":"Deletes the suite. The Codeless tests attached to it are not deleted — only the suite grouping.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID to delete.","type":"integer","format":"int32","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Delete a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"deleteV1LabsuitesId"}},"/v1/labsuites/{id}/tests":{"get":{"summary":"List tests in a Codeless suite","description":"Returns the Codeless tests attached to a suite, with pagination.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID.","type":"integer","format":"int32","required":true},{"in":"query","name":"offset","description":"Skip this many tests.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of tests to return.","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List tests in a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_LabTestList"}},"401":{"description":"Authentication required"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"getV1LabsuitesIdTests"},"post":{"summary":"Add tests to a Codeless suite","description":"Attaches one or more existing Codeless tests to a suite. Pass `test_ids` as a comma-separated list.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabsuitesIdTests","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabsuitesIdTests"}}],"responses":{"201":{"description":"Add tests to a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Missing test_ids"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"postV1LabsuitesIdTests"}},"/v1/labsuites/{id}/tests/{testid}":{"delete":{"summary":"Remove a test from a Codeless suite","description":"Detaches a single Codeless test from a suite. The test itself is preserved.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID.","type":"integer","format":"int32","required":true},{"in":"path","name":"testid","description":"Numeric Codeless test ID to detach.","type":"integer","format":"int32","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Remove a test from a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"},"404":{"description":"Suite or test not found"}},"tags":["Codeless suites"],"operationId":"deleteV1LabsuitesIdTestsTestid"}},"/v1/labsuites/{id}/browsers":{"get":{"summary":"Get browsers for a Codeless suite","description":"Returns the list of browsers the suite is configured to run on.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get browsers for a Codeless suite","schema":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Browser"}}},"401":{"description":"Authentication required"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"getV1LabsuitesIdBrowsers"},"post":{"summary":"Update browsers for a Codeless suite","description":"Replaces the browser set attached to a suite. Every test in the suite will run on the new browser list at next trigger.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric suite ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabsuitesIdBrowsers","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabsuitesIdBrowsers"}}],"responses":{"201":{"description":"Update browsers for a Codeless suite","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Missing browser_ids"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Suite not found"}},"tags":["Codeless suites"],"operationId":"postV1LabsuitesIdBrowsers"}},"/v1/lab":{"get":{"summary":"List your Codeless tests","description":"Paginated list of every Codeless test (a.k.a. Lab test) on the account. Codeless tests are recorded in TestingBot's in-browser recorder and can be scheduled on a cron, fired via API, or chained into suites.","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many tests from the start of the result set.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of tests to return (max 500).","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List your Codeless tests","schema":{"$ref":"#/definitions/Testingbot_Entities_LabTestList"}},"401":{"description":"Authentication required"}},"tags":["Codeless tests"],"operationId":"getV1Lab"},"post":{"summary":"Create a Codeless test","description":"Creates a new Codeless test. Pass `test[name]` and either `test[url]` (target URL the test visits) or `file` (Selenium IDE export to import). Optional `test[ai_prompt]` lets you describe what the AI test agent should verify in plain English.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1Lab","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1Lab"}}],"responses":{"201":{"description":"Create a Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_LabCreateAck"}},"400":{"description":"Validation error"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"}},"tags":["Codeless tests"],"operationId":"postV1Lab"}},"/v1/lab/{id}/schedule":{"post":{"summary":"Set or update a Codeless test schedule","description":"Schedules a Codeless test to run on a recurring interval. Choose between once / daily / weekly presets or a raw cron expression.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabIdSchedule","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabIdSchedule"}}],"responses":{"201":{"description":"Set or update a Codeless test schedule","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Missing day/hour for weekly"},"401":{"description":"Authentication required"},"402":{"description":"Insufficient credits"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"postV1LabIdSchedule"}},"/v1/lab/{id}/alert":{"post":{"summary":"Add an alert to a Codeless test","description":"Adds a notification channel (email, SMS, or callback URL) that fires when a scheduled run fails. Use PUT to modify an existing alert.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabIdAlert","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabIdAlert"}}],"responses":{"201":{"description":"Add an alert to a Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Alert already exists — use PUT"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"postV1LabIdAlert"},"put":{"summary":"Update an existing alert","description":"Replaces the alert configuration on a Codeless test. POST to /alert creates one; PUT updates it.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"putV1LabIdAlert","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1LabIdAlert"}}],"responses":{"200":{"description":"Update an existing alert","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"putV1LabIdAlert"}},"/v1/lab/{id}/report":{"post":{"summary":"Add a daily report config to a Codeless test","description":"Configures a recurring email report summarising pass/fail rate for this Codeless test. Use PUT to update.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabIdReport","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabIdReport"}}],"responses":{"201":{"description":"Add a daily report config to a Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Validation error"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"postV1LabIdReport"},"put":{"summary":"Update a daily report config","description":"Replaces the report destination/schedule for a Codeless test.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"putV1LabIdReport","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1LabIdReport"}}],"responses":{"200":{"description":"Update a daily report config","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"putV1LabIdReport"}},"/v1/lab/{id}/trigger":{"post":{"summary":"Run a specific Codeless test","description":"Triggers an immediate run of a Codeless test on the browsers configured for it. Returns a `job_id` you can poll with `GET /v1/jobs/:id`.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID to run.","type":"integer","format":"int32","required":true},{"name":"postV1LabIdTrigger","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabIdTrigger"}}],"responses":{"201":{"description":"Run a specific Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_LabRunAck"}},"401":{"description":"Authentication required"},"402":{"description":"Insufficient credits"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"postV1LabIdTrigger"}},"/v1/lab/{id}/steps":{"get":{"summary":"List Codeless test steps","description":"Returns the recorded Selenium-IDE steps for a Codeless test, with pagination.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"in":"query","name":"offset","description":"Skip this many steps.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of steps to return.","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List Codeless test steps","schema":{"$ref":"#/definitions/Testingbot_Entities_LabTestStepList"}},"401":{"description":"Authentication required"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"getV1LabIdSteps"},"post":{"summary":"Replace the Codeless test's steps","description":"Deletes the test's existing steps and replaces them with the provided array. Useful for programmatic editing of recorded tests.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabIdSteps","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabIdSteps"}}],"responses":{"201":{"description":"Replace the Codeless test's steps","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Missing steps"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"postV1LabIdSteps"}},"/v1/lab/{id}/stop":{"put":{"summary":"Stop a running Codeless test","description":"Force-stops an in-flight Codeless test run. Optional `browser_id` stops only the run on a specific browser.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"putV1LabIdStop","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1LabIdStop"}}],"responses":{"200":{"description":"Stop a running Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"putV1LabIdStop"}},"/v1/lab/{id}/browsers":{"get":{"summary":"Get browsers for a Codeless test","description":"Returns the list of browsers this Codeless test is configured to run on.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get browsers for a Codeless test","schema":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Browser"}}},"401":{"description":"Authentication required"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"getV1LabIdBrowsers"},"post":{"summary":"Update browsers for a Codeless test","description":"Replaces the entire browser set attached to this Codeless test. Pass `browser_ids` as a comma-separated list of IDs from `/v1/browsers`.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true},{"name":"postV1LabIdBrowsers","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabIdBrowsers"}}],"responses":{"201":{"description":"Update browsers for a Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"400":{"description":"Missing browser_ids"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"postV1LabIdBrowsers"}},"/v1/lab/trigger_all":{"post":{"summary":"Run all Codeless tests","description":"Queues a run of every Codeless test on the account. Returns a job_id that aggregates the results — poll via `GET /v1/jobs/:id`. Optional `url` overrides each test's base URL for this run.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1LabTriggerAll","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1LabTriggerAll"}}],"responses":{"201":{"description":"Run all Codeless tests","schema":{"$ref":"#/definitions/Testingbot_Entities_LabRunAck"}},"401":{"description":"Authentication required"},"402":{"description":"Insufficient credits"},"403":{"description":"Account is read-only"}},"tags":["Codeless tests"],"operationId":"postV1LabTriggerAll"}},"/v1/lab/{id}":{"get":{"summary":"Get a specific Codeless test","description":"Returns a single Codeless test's configuration: schedule, alerts, attached browsers, and timestamps. Use the steps endpoint to retrieve the actual test recording.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID.","type":"integer","format":"int32","required":true}],"responses":{"200":{"description":"Get a specific Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_LabTest"}},"401":{"description":"Authentication required"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"getV1LabId"},"delete":{"summary":"Delete a Codeless test","description":"Permanently deletes a Codeless test and its steps. Test runs in history remain.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID to delete.","type":"integer","format":"int32","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Delete a Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"deleteV1LabId"},"put":{"summary":"Update a Codeless test","description":"Updates a Codeless test's metadata: name, target URL, cron schedule, enabled state. Accepts either a numeric Codeless test ID or a WebDriver session_id of a test run that originated from this Codeless test.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric Codeless test ID or WebDriver session_id.","type":"string","required":true},{"name":"putV1LabId","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1LabId"}}],"responses":{"200":{"description":"Update a Codeless test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Codeless tests"],"operationId":"putV1LabId"}},"/v1/builds":{"get":{"summary":"List your builds","description":"Returns a paginated list of test builds. A build is an aggregation of test cases that share the same `capabilities.build` identifier, useful for grouping CI runs.","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many builds from the start of the result set.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of builds to return (max 500).","type":"integer","format":"int32","default":10,"required":false}],"responses":{"200":{"description":"List your builds","schema":{"$ref":"#/definitions/Testingbot_Entities_BuildList"}},"401":{"description":"Authentication required"}},"tags":["Builds"],"operationId":"getV1Builds"}},"/v1/builds/*id":{"get":{"summary":"Get tests for a build","description":"Returns all test cases that belong to a single build, with pagination. The build can be referenced by either its numeric internal ID or the string identifier you set via `capabilities.build`.","produces":["application/json"],"parameters":[{"in":"query","name":"id","description":"Numeric build ID or string build identifier.","type":"string","required":true},{"in":"query","name":"offset","description":"Skip this many tests in the build.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of tests to return (max 500).","type":"integer","format":"int32","default":10,"required":false},{"in":"query","name":"skip_fields","description":"Comma-separated fields to omit from each test (logs, thumbs).","type":"string","required":false}],"responses":{"200":{"description":"Get tests for a build","schema":{"$ref":"#/definitions/Testingbot_Entities_TestCaseList"}},"401":{"description":"Authentication required"},"404":{"description":"Build not found"}},"tags":["Builds"],"operationId":"getV1Builds*id"},"delete":{"summary":"Delete a build","description":"Permanently deletes a build and every test, asset (video, logs, screenshots) attached to it. This action cannot be undone.","produces":["application/json"],"parameters":[{"in":"query","name":"id","description":"Numeric build ID or string build identifier to delete.","type":"string","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Delete a build","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"},"404":{"description":"Build not found"}},"tags":["Builds"],"operationId":"deleteV1Builds*id"}},"/v1/tests":{"get":{"summary":"List your tests","description":"Paginated list of every test session belonging to the authenticated account, newest first. Filter by `browser_id`, `group`, or `build` to narrow the result. Use `since` to fetch only tests updated after a UNIX timestamp (poll-friendly).","produces":["application/json"],"parameters":[{"in":"query","name":"offset","description":"Skip this many tests from the start of the result set.","type":"integer","format":"int32","default":0,"required":false},{"in":"query","name":"count","description":"Number of tests to return (max 500).","type":"integer","format":"int32","default":10,"required":false},{"in":"query","name":"since","description":"UNIX timestamp; return only tests updated at or after this time.","type":"integer","format":"int32","required":false},{"in":"query","name":"browser_id","description":"Filter to tests that ran on this browser_id (from /v1/browsers).","type":"integer","format":"int32","required":false},{"in":"query","name":"group","description":"Filter to tests tagged with this group name.","type":"string","required":false},{"in":"query","name":"build","description":"Filter to tests in this build (matches `capabilities.build`).","type":"string","required":false},{"in":"query","name":"skip_fields","description":"Comma-separated fields to omit (logs, thumbs).","type":"string","required":false}],"responses":{"200":{"description":"List your tests","schema":{"$ref":"#/definitions/Testingbot_Entities_TestCaseList"}},"401":{"description":"Authentication required"},"404":{"description":"Group or build not found"}},"tags":["Tests"],"operationId":"getV1Tests"},"post":{"summary":"Create a test record (manual sessions)","description":"Creates a TestCase record from outside the WebDriver/Appium flow. Mainly used by clients that want to log a manual or external test result against their TestingBot account. Most users will not need this — the normal flow is to start a Selenium/Appium session, and the record is created automatically.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"postV1Tests","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1Tests"}}],"responses":{"201":{"description":"Create a test record (manual sessions)","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"400":{"description":"Validation error"}},"tags":["Tests"],"operationId":"postV1Tests"}},"/v1/tests/{id}":{"put":{"summary":"Update a test","description":"Updates a test's metadata after it's been recorded. Use this to mark a test as passed/failed from the test runner, attach groups/tags, set a build identifier, or add a status message. Accepts either a numeric test ID or a WebDriver session_id.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric test ID or WebDriver session_id (UUID).","type":"string","required":true},{"name":"putV1TestsId","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1TestsId"}}],"responses":{"200":{"description":"Update a test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Tests"],"operationId":"putV1TestsId"},"post":{"summary":"Update a test (POST alias)","description":"Alias of `PUT /v1/tests/:id` for clients that cannot send PUT requests (some older HTTP libraries). Same body schema and behavior — see PUT for the canonical form.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric test ID or WebDriver session_id (UUID).","type":"string","required":true},{"name":"postV1TestsId","in":"body","required":true,"schema":{"$ref":"#/definitions/postV1TestsId"}}],"responses":{"201":{"description":"Update a test (POST alias)","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Tests"],"operationId":"postV1TestsId"},"get":{"summary":"Get a specific test","description":"Returns the full detail record for a single test session: status, environment (browser/OS or device/platform), assets (video, logs, screenshots), groups, build, and duration. Accepts either the numeric test ID or the WebDriver session_id.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric test ID or WebDriver session_id (UUID).","type":"string","required":true},{"in":"query","name":"skip_fields","description":"Comma-separated fields to omit from the response (logs, thumbs, visual_run, groups).","type":"string","required":false}],"responses":{"200":{"description":"Get a specific test","schema":{"$ref":"#/definitions/Testingbot_Entities_TestCase"}},"401":{"description":"Authentication required"},"404":{"description":"Test not found"}},"tags":["Tests"],"operationId":"getV1TestsId"},"delete":{"summary":"Delete a test","description":"Permanently deletes a test session and every associated asset (video, logs, screenshots). This action cannot be undone.","produces":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric test ID or WebDriver session_id of the test to delete.","type":"string","required":true}],"responses":{"401":{"description":"Authentication required"},"204":{"description":"Delete a test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"403":{"description":"Account is read-only"},"404":{"description":"Test not found"}},"tags":["Tests"],"operationId":"deleteV1TestsId"}},"/v1/tests/{id}/stop":{"put":{"summary":"Stop a running test","description":"Terminates an in-flight test session. The test is marked complete; any assets gathered (video, logs, screenshots) become available for download. Returns 404 if the test has already finished.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"in":"path","name":"id","description":"Numeric test ID or WebDriver session_id of the test to stop.","type":"string","required":true}],"responses":{"200":{"description":"Stop a running test","schema":{"$ref":"#/definitions/Testingbot_Entities_Ack"}},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"},"404":{"description":"Test not found or already finished"}},"tags":["Tests"],"operationId":"putV1TestsIdStop"}},"/v1/user":{"get":{"summary":"Get your user info","description":"Returns the data associated with the authenticated account: name, plan, billing details, remaining credits, and concurrency caps.","produces":["application/json"],"responses":{"200":{"description":"Get your user info","schema":{"$ref":"#/definitions/Testingbot_Entities_User"}},"401":{"description":"Authentication required"}},"tags":["User"],"operationId":"getV1User"},"put":{"summary":"Update your user info","description":"Updates the authenticated account. Only `first_name` and `last_name` are mutable through this endpoint; other profile fields require the dashboard.","produces":["application/json"],"consumes":["application/json"],"parameters":[{"name":"putV1User","in":"body","required":true,"schema":{"$ref":"#/definitions/putV1User"}}],"responses":{"200":{"description":"Update your user info","schema":{"$ref":"#/definitions/Testingbot_Entities_UserUpdate"}},"400":{"description":"Validation error"},"401":{"description":"Authentication required"},"403":{"description":"Account is read-only"}},"tags":["User"],"operationId":"putV1User"}},"/v1/user/keys":{"get":{"summary":"Get your API key and secret","description":"Returns the API client key and secret for the authenticated account. Useful for confirming the credentials currently in use, but never embed this response in client-side code.","produces":["application/json"],"responses":{"200":{"description":"Get your API key and secret"}},"tags":["User"],"operationId":"getV1UserKeys"}}},"definitions":{"Testingbot_Entities_Device":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric device ID."},"name":{"type":"string","description":"Marketing name (e.g. \"iPhone 15 Pro\")."},"model":{"type":"string","description":"Device model identifier."},"manufacturer":{"type":"string","description":"OEM (e.g. \"Apple\", \"Samsung\")."},"platform_name":{"type":"string","description":"Mobile OS family (e.g. \"iOS\", \"Android\")."},"platform_version":{"type":"string","description":"OS version (e.g. \"17.4\", \"14\")."},"screen_size":{"type":"string","description":"Display size in inches (e.g. \"6.1\")."},"screen_resolution":{"type":"string","description":"Display resolution (e.g. \"1170x2532\")."}},"required":["id","name","model","manufacturer","platform_name","platform_version","screen_size","screen_resolution"],"description":"Testingbot_Entities_Device model"},"Testingbot_Entities_Browser":{"type":"object","properties":{"selenium_name":{"type":"string","description":"Capability value to send as `browserName` in WebDriver."},"name":{"type":"string","description":"Human-readable browser identifier (e.g. \"firefox\", \"iexplore\")."},"version":{"type":"integer","format":"int32","description":"Major version number."},"long_version":{"type":"string","description":"Full version string (e.g. \"121.0.6167.184\")."},"platform":{"type":"string","description":"Operating system (e.g. \"WINDOWS\", \"MAC\", \"LINUX\")."},"browser_id":{"type":"integer","format":"int32","description":"Unique TestingBot browser ID used to attach browsers to Codeless tests."}},"required":["selenium_name","name","version","long_version","platform","browser_id"],"description":"Testingbot_Entities_Browser model"},"Testingbot_Entities_Tunnel":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric tunnel ID."},"state":{"type":"string","description":"Tunnel lifecycle state (READY, STOPPED, …)."},"launched":{"type":"string","format":"date-time","description":"When the tunnel was launched."},"tunnel_id":{"type":"string","description":"Public tunnel identifier surfaced in the dashboard."},"identifier":{"type":"string","description":"Custom name passed via --tunnel-identifier on the client."},"metadata":{"type":"object","description":"Free-form metadata (client version, OS, region) reported by the tunnel binary."}},"required":["id","state","launched","tunnel_id","identifier","metadata"],"description":"Testingbot_Entities_Tunnel model"},"Testingbot_Entities_Ack":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the operation succeeded."}},"required":["success"],"description":"Testingbot_Entities_Ack model"},"Testingbot_Entities_Job":{"type":"object","properties":{"status":{"type":"string","description":"Job state (QUEUED, RUNNING, FINISHED, FAILED)."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"success":{"type":"boolean","description":"Aggregate pass/fail across all triggered tests; null until FINISHED."},"test_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Test IDs spawned by this job."},"errors":{"type":"array","items":{"type":"object"},"description":"Per-test failure detail (step, browser, time)."}},"required":["status","created_at","updated_at","success","test_ids","errors"],"description":"Testingbot_Entities_Job model"},"Testingbot_Entities_Team":{"type":"object","properties":{"concurrency":{"allOf":[{"$ref":"#/definitions/Testingbot_Entities_TeamConcurrencyBlock"}],"description":"Allowed vs current concurrency caps for the team, split in VM and physical device sessions."}},"required":["concurrency"],"description":"Testingbot_Entities_Team model"},"Testingbot_Entities_TeamConcurrencyBlock":{"type":"object","properties":{"allowed":{"allOf":[{"$ref":"#/definitions/Testingbot_Entities_TeamConcurrency"}],"description":"Maximum simultaneous sessions the plan allows."},"current":{"allOf":[{"$ref":"#/definitions/Testingbot_Entities_TeamConcurrency"}],"description":"Sessions in use right now."}},"required":["allowed","current"]},"Testingbot_Entities_TeamConcurrency":{"type":"object","properties":{"vms":{"type":"integer","format":"int32","description":"VM-based concurrent sessions."},"physical":{"type":"integer","format":"int32","description":"Physical device concurrent sessions."}},"required":["vms","physical"]},"Testingbot_Entities_TeamMemberList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_TeamMember"},"description":"Team member accounts."},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_TeamMemberList model"},"Testingbot_Entities_TeamMember":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric user ID."},"first_name":{"type":"string","description":"Given name."},"last_name":{"type":"string","description":"Family name."},"email":{"type":"string","description":"Account email."},"credits":{"type":"integer","format":"int32","description":"Remaining VM credit seconds."},"device_credits":{"type":"integer","format":"int32","description":"Remaining physical-device credit seconds."},"isPaid":{"type":"boolean","description":"Whether the account has an active paid plan."},"verified":{"type":"boolean","description":"Whether the account email has been verified."},"parent_id":{"type":"integer","format":"int32","description":"Parent (team owner) user ID; 0 means this user is the team owner."}},"required":["id","first_name","last_name","email","credits","device_credits","isPaid","verified","parent_id"],"description":"Testingbot_Entities_TeamMember model"},"Testingbot_Entities_Meta":{"type":"object","properties":{"offset":{"type":"integer","format":"int32","description":"Number of items skipped from the start of the result set."},"count":{"type":"integer","format":"int32","description":"Items returned in this page (matches the requested `count` query param)."},"total":{"type":"integer","format":"int32","description":"Total number of items available across all pages."}},"required":["offset","count","total"]},"Testingbot_Entities_TeamCredentialReset":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether keys were rotated."},"client_key":{"type":"string","description":"The new API client key. Save this — the old key stops working immediately."}},"required":["success","client_key"],"description":"Testingbot_Entities_TeamCredentialReset model"},"postV1TeamManagementUsers":{"type":"object","properties":{"email":{"type":"string","description":"Email address for the new account; must be unique across TestingBot."},"password":{"type":"string","description":"Initial password for the new user."},"first_name":{"type":"string","description":"New user's given name."},"last_name":{"type":"string","description":"New user's family name."},"concurrency":{"type":"integer","format":"int32","description":"Max parallel VM sessions (≤ team owner's `maxParallel`)."},"concurrencyPhysical":{"type":"integer","format":"int32","description":"Max parallel physical-device sessions (≤ team owner's `maxParallelDevice`)."}},"required":["email","password"],"description":"Create a user in your team"},"putV1TeamManagementUsersId":{"type":"object","properties":{"first_name":{"type":"string","description":"New given name."},"last_name":{"type":"string","description":"New family name."},"email":{"type":"string","description":"New email address."},"password":{"type":"string","description":"New password."},"credits":{"type":"integer","format":"int32","description":"Allocated VM credit seconds (≤ team owner's remaining VM credits)."},"device_credits":{"type":"integer","format":"int32","description":"Allocated physical-device credit seconds (≤ team owner's remaining device credits)."},"concurrency":{"type":"integer","format":"int32","description":"Max parallel VM sessions for this user."},"concurrencyPhysical":{"type":"integer","format":"int32","description":"Max parallel physical-device sessions for this user."}},"description":"Update a user in your team"},"postV1Storage":{"type":"object","properties":{"file":{"type":"file","description":"Multipart binary upload of an .apk or .ipa."},"url":{"type":"string","description":"Public HTTPS URL TestingBot will download the binary from."}},"description":"Upload an app to storage"},"Testingbot_Entities_StorageFile":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric storage object ID."},"app_url":{"type":"string","description":"TestingBot storage URL (`tb://<appkey>`) — pass as a capability to reference this app in mobile tests."},"url":{"type":"string","description":"Signed HTTPS URL to download the binary directly."},"filename":{"type":"string","description":"Original uploaded filename."},"type":{"type":"string","description":"Detected app type (apk, ipa, zip)."},"version":{"type":"string","description":"CFBundleShortVersionString / versionName extracted from the binary."},"min_device_version":{"type":"string","description":"Minimum OS version required by the app."},"thumb":{"type":"string","description":"App icon (signed PNG URL)."},"created_at":{"type":"string","format":"date-time","description":"Upload timestamp."},"state":{"type":"string","description":"Processing state (PROCESSING, READY)."},"sim_only":{"type":"boolean","description":"True for iOS simulator-only IPAs (no signing)."}},"required":["id","app_url","url","filename","type","version","min_device_version","thumb","created_at","state","sim_only"],"description":"Testingbot_Entities_StorageFile model"},"postV1Storage*":{"type":"object","properties":{"splat":{"type":"integer","format":"int32"},"file":{"type":"file","description":"Multipart binary replacement."},"url":{"type":"string","description":"Public HTTPS URL to fetch the new binary from."}},"required":["splat"],"description":"Update an app binary by appkey"},"Testingbot_Entities_StorageFileList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_StorageFile"},"description":"Storage objects for this page."},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_StorageFileList model"},"Testingbot_Entities_ScreenshotList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Screenshot"}},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_ScreenshotList model"},"Testingbot_Entities_Screenshot":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique screenshot job ID."},"url":{"type":"string","description":"URL the screenshot was taken from."},"state":{"type":"string","description":"Processing state."},"wait_time":{"type":"integer","format":"int32","description":"Seconds the browser waited before snapping."},"resolution":{"type":"string","description":"Browser viewport resolution."},"screenshots":{"type":"array","items":{"type":"object"},"description":"Per-browser screenshot results with download URLs."},"created_at":{"type":"string","format":"date-time"}},"required":["id","url","state","wait_time","resolution","screenshots","created_at"],"description":"Testingbot_Entities_Screenshot model"},"postV1Screenshots":{"type":"object","properties":{"url":{"type":"string","description":"Page URL to screenshot."},"resolution":{"type":"string","description":"Browser viewport (e.g. \"1920x1080\")."},"browsers":{"type":"array","description":"Array of `{ browser, version, os }` triples (or `browser_id`s) to render with.","items":{"type":"string"}},"wait_time":{"type":"integer","format":"int32","description":"Seconds to wait after page load before snapping.","default":0},"fullpage":{"type":"boolean","description":"Capture the entire scrollable page instead of just the viewport.","default":false},"callback_url":{"type":"string","description":"POST callback URL invoked when the batch finishes processing."}},"required":["url","resolution","browsers"],"description":"Capture a new screenshot batch"},"Testingbot_Entities_LabSuiteList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_LabSuite"}},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_LabSuiteList model"},"Testingbot_Entities_LabSuite":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric Codeless suite ID."},"name":{"type":"string","description":"Suite name."},"enabled":{"type":"boolean","description":"Whether scheduled runs are active."},"cron":{"type":"string","description":"Cron expression for scheduled runs."},"test_count":{"type":"integer","format":"int32","description":"Number of Codeless tests attached."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_run":{"type":"string","format":"date-time"},"alerts":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_LabAlert"}}},"required":["id","name","enabled","cron","test_count","created_at","updated_at","last_run","alerts"],"description":"Testingbot_Entities_LabSuite model"},"Testingbot_Entities_LabAlert":{"type":"object","properties":{"type":{"type":"string","description":"Alert channel (EMAIL, API, SMS)."},"value":{"type":"string","description":"Channel value: email address, callback URL, or phone number."},"level":{"type":"string","description":"When to send (IMMEDIATELY, DAILY)."}},"required":["type","value","level"]},"postV1Labsuites":{"type":"object","properties":{"suite":{"type":"object","description":"Suite attributes.","properties":{"name":{"type":"string","description":"Suite name."},"cron":{"type":"string","description":"Cron expression for scheduled suite runs."},"screenshot":{"type":"boolean","description":"Take screenshots at every step in every test."},"video":{"type":"boolean","description":"Record video for tests in this suite."},"idletimeout":{"type":"integer","format":"int32","description":"Idle timeout in seconds before tests are aborted."},"screenresolution":{"type":"string","description":"Browser viewport for every test in the suite."}},"required":["name"]}},"required":["suite"],"description":"Create a Codeless suite"},"Testingbot_Entities_LabSuiteCreateAck":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether creation succeeded."},"suite_id":{"type":"integer","format":"int32","description":"ID of the newly created Codeless suite."}},"required":["success","suite_id"],"description":"Testingbot_Entities_LabSuiteCreateAck model"},"Testingbot_Entities_LabRunAck":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the run was queued successfully."},"job_id":{"type":"integer","format":"int32","description":"Job ID — poll `GET /v1/jobs/:id` for progress."}},"required":["success","job_id"],"description":"Testingbot_Entities_LabRunAck model"},"Testingbot_Entities_LabTestList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_LabTest"}},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_LabTestList model"},"Testingbot_Entities_LabTest":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric Codeless test ID."},"name":{"type":"string","description":"Test name."},"url":{"type":"string","description":"Target URL the test runs against."},"enabled":{"type":"boolean","description":"Whether scheduled runs are active."},"cron":{"type":"string","description":"Cron expression for scheduled runs; null if unscheduled."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_run":{"type":"string","format":"date-time","description":"Most recent run timestamp."},"alerts":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_LabAlert"},"description":"Configured alert destinations."},"browsers":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Browser"},"description":"Browsers this test is configured to run on."}},"required":["id","name","url","enabled","cron","created_at","updated_at","last_run","alerts","browsers"],"description":"Testingbot_Entities_LabTest model"},"postV1LabsuitesIdTests":{"type":"object","properties":{"test_ids":{"type":"string","description":"Comma-separated list of Codeless test IDs to attach."}},"required":["test_ids"],"description":"Add tests to a Codeless suite"},"postV1LabsuitesIdBrowsers":{"type":"object","properties":{"browser_ids":{"type":"string","description":"Comma-separated list of browser_ids the suite should run on."}},"required":["browser_ids"],"description":"Update browsers for a Codeless suite"},"postV1Lab":{"type":"object","properties":{"test":{"type":"object","description":"Test attributes.","properties":{"name":{"type":"string","description":"Test name."},"url":{"type":"string","description":"Target URL to test (required if no `file` is uploaded)."},"cron":{"type":"string","description":"Cron expression for scheduled runs."},"screenshot":{"type":"boolean","description":"Take screenshots at every step."},"video":{"type":"boolean","description":"Record a video of the test."},"idletimeout":{"type":"integer","format":"int32","description":"Seconds of idle time before the runner aborts the test."},"screenresolution":{"type":"string","description":"Browser viewport (e.g. \"1920x1080\")."},"ai_prompt":{"type":"string","description":"Plain-English instruction for the AI test agent."}}},"file":{"type":"file","description":"Selenium IDE `.side` export to import as the test's steps."}},"description":"Create a Codeless test"},"Testingbot_Entities_LabCreateAck":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether creation succeeded."},"lab_test_id":{"type":"integer","format":"int32","description":"ID of the newly created Codeless test."}},"required":["success","lab_test_id"],"description":"Testingbot_Entities_LabCreateAck model"},"postV1LabIdSchedule":{"type":"object","properties":{"type":{"type":"string","description":"Schedule preset; use \"custom\" with `cronFormat` for fine control.","enum":["once","daily","weekly","custom"]},"day":{"type":"string","description":"Date (YYYY-MM-DD) for \"once\" or weekday for \"weekly\"."},"hour":{"type":"string","description":"Time (HH:MM) for \"once\", \"daily\", or \"weekly\"."},"cronFormat":{"type":"string","description":"Raw cron expression (5-field) used when `type=custom`."}},"description":"Set or update a Codeless test schedule"},"postV1LabIdAlert":{"type":"object","properties":{"kind":{"type":"string","description":"Alert channel.","enum":["EMAIL","API","SMS"]},"level":{"type":"string","description":"When to send (every failure vs. daily digest).","enum":["IMMEDIATELY","DAILY"]},"content":{"type":"string","description":"Destination — email address, callback URL, or phone number."}},"required":["kind","level","content"],"description":"Add an alert to a Codeless test"},"putV1LabIdAlert":{"type":"object","properties":{"kind":{"type":"string","description":"Alert channel.","enum":["EMAIL","API","SMS"]},"level":{"type":"string","description":"When to send.","enum":["IMMEDIATELY","DAILY"]},"content":{"type":"string","description":"Updated destination value."}},"description":"Update an existing alert"},"postV1LabIdReport":{"type":"object","properties":{"email":{"type":"string","description":"Email address that receives the report."},"cron":{"type":"string","description":"Cron expression for when to send the report (defaults to daily)."}},"required":["email"],"description":"Add a daily report config to a Codeless test"},"putV1LabIdReport":{"type":"object","properties":{"email":{"type":"string","description":"Updated email address."},"cron":{"type":"string","description":"Updated cron expression."}},"description":"Update a daily report config"},"postV1LabIdTrigger":{"type":"object","properties":{"url":{"type":"string","description":"Override the test's base URL for this run only."}},"description":"Run a specific Codeless test"},"Testingbot_Entities_LabTestStepList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_LabTestStep"}},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_LabTestStepList model"},"Testingbot_Entities_LabTestStep":{"type":"object","properties":{"test_order":{"type":"integer","format":"int32","description":"Zero-based step index."},"cmd":{"type":"string","description":"Selenium IDE command (open, click, type, verifyTitle, …)."},"locator":{"type":"string","description":"Selenium target (id=foo, xpath=//div, …)."},"value":{"type":"string","description":"Selenium value parameter when required."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["test_order","cmd","locator","value","created_at","updated_at"]},"postV1LabIdSteps":{"type":"object","properties":{"steps":{"type":"array","description":"Ordered list of steps; each is `{ order:, cmd:, locator:, value: }`.","items":{"type":"string"}}},"required":["steps"],"description":"Replace the Codeless test's steps"},"putV1LabIdStop":{"type":"object","properties":{"browser_id":{"type":"integer","format":"int32","description":"Only stop the run on this browser_id (omit to stop all)."}},"description":"Stop a running Codeless test"},"postV1LabIdBrowsers":{"type":"object","properties":{"browser_ids":{"type":"string","description":"Comma-separated list of browser_ids the test should run on."}},"required":["browser_ids"],"description":"Update browsers for a Codeless test"},"postV1LabTriggerAll":{"type":"object","properties":{"url":{"type":"string","description":"Override base URL for every queued test."}},"description":"Run all Codeless tests"},"putV1LabId":{"type":"object","properties":{"test":{"type":"object","description":"Updated fields.","properties":{"name":{"type":"string","description":"New test name."},"url":{"type":"string","description":"New target URL."},"cron":{"type":"string","description":"New cron expression."},"enabled":{"type":"boolean","description":"Enable or pause scheduled runs."}}}},"required":["test"],"description":"Update a Codeless test"},"Testingbot_Entities_BuildList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_Build"},"description":"Builds for this page."},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_BuildList model"},"Testingbot_Entities_Build":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric build ID."},"build_id":{"type":"string","description":"User-supplied build identifier (capabilities.build)."},"created_at":{"type":"string","format":"date-time","description":"When the first test in the build started."},"completed_at":{"type":"string","format":"date-time","description":"When the last test finished; null while builds are in progress."},"status":{"type":"string","description":"Aggregate status across all tests in the build."},"session_id":{"type":"string","description":"Selenium session ID of the first test in the build."},"duration":{"type":"integer","format":"int32","description":"Sum of all test durations in seconds."},"success":{"type":"boolean","description":"True if every test in the build passed."},"total_tests":{"type":"integer","format":"int32","description":"Total number of tests in the build."},"failed_tests":{"type":"integer","format":"int32","description":"Tests that failed."},"passed_tests":{"type":"integer","format":"int32","description":"Tests that passed."}},"required":["id","build_id","created_at","completed_at","status","session_id","duration","success","total_tests","failed_tests","passed_tests"]},"Testingbot_Entities_TestCaseList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/Testingbot_Entities_TestCase"},"description":"Test sessions for this page."},"meta":{"$ref":"#/definitions/Testingbot_Entities_Meta"}},"required":["data","meta"],"description":"Testingbot_Entities_TestCaseList model"},"Testingbot_Entities_TestCase":{"type":"object","properties":{"id":{"type":"integer","format":"int32","description":"Unique numeric test ID."},"session_id":{"type":"string","description":"Selenium / WebDriver session ID (UUID)."},"name":{"type":"string","description":"Human-readable test name set via capabilities or `update_test`."},"state":{"type":"string","description":"Lifecycle state (RUNNING, COMPLETE, TIMEOUT, …)."},"success":{"type":"boolean","description":"Whether the test passed."},"status_id":{"type":"integer","format":"int32","description":"Numeric status code (0=fail, 1=pass, 2=unknown)."},"status_message":{"type":"string","description":"Failure reason or arbitrary status set via `test[status_message]`."},"created_at":{"type":"string","format":"date-time","description":"When the test session started."},"completed_at":{"type":"string","format":"date-time","description":"When the session ended; null while running."},"duration":{"type":"integer","format":"int32","description":"Total run time in seconds."},"browser":{"type":"string","description":"Browser identifier (e.g. \"iexplore\", \"firefox\")."},"browser_version":{"type":"integer","format":"int32","description":"Browser major version."},"os":{"type":"string","description":"OS (e.g. \"WINDOWS\", \"MAC\")."},"device_name":{"type":"string","description":"Mobile device name when the session ran on a physical device; null otherwise."},"platform_name":{"type":"string","description":"Mobile OS name; null on desktop."},"build":{"type":"string","description":"Build identifier (free-form string set via capabilities)."},"groups":{"type":"array","items":{"type":"string"},"description":"Tag/group names attached to the test."},"video":{"type":"string","description":"Signed S3 URL to the recorded video, or false if video was disabled."},"thumbs":{"type":"array","items":{"type":"string"},"description":"Signed S3 URLs to screenshot thumbnails."},"logs":{"type":"object","description":"Map of log names → signed S3 URLs (selenium, browser, …)."},"assets_available":{"type":"boolean","description":"Whether assets (video, logs, screenshots) have finished processing."},"extra":{"type":"string","description":"Arbitrary metadata string set via `test[extra]`."},"type":{"type":"string","description":"Driver type (WEBDRIVER, APPIUM)."}},"required":["id","session_id","name","state","success","status_id","status_message","created_at","completed_at","duration","browser","browser_version","os","device_name","platform_name","build","groups","video","thumbs","logs","assets_available","extra","type"],"description":"Testingbot_Entities_TestCase model"},"putV1TestsId":{"type":"object","properties":{"test":{"type":"object","description":"Fields to update.","properties":{"name":{"type":"string","description":"Human-readable test name."},"success":{"type":"boolean","description":"true=pass, false=fail."},"status_message":{"type":"string","description":"Failure reason or arbitrary status text."},"extra":{"type":"string","description":"Arbitrary metadata."},"build":{"type":"string","description":"Build identifier to associate this test with."},"public":{"type":"boolean","description":"When true, makes the test publicly viewable via share URL."}}},"groups":{"type":"string","description":"Comma-separated string or array of tag/group names to attach to the test."},"build":{"type":"string","description":"Build identifier (alternative location to `test[build]`)."}},"description":"Update a test"},"postV1TestsId":{"type":"object","properties":{"test":{"type":"object","description":"Fields to update.","properties":{"name":{"type":"string","description":"Human-readable test name."},"success":{"type":"boolean","description":"true=pass, false=fail."},"status_message":{"type":"string","description":"Failure reason or arbitrary status text."},"extra":{"type":"string","description":"Arbitrary metadata."},"build":{"type":"string","description":"Build identifier to associate this test with."},"public":{"type":"boolean","description":"When true, makes the test publicly viewable via share URL."}}},"groups":{"type":"string","description":"Comma-separated string or array of tag/group names to attach to the test."}},"description":"Update a test (POST alias)"},"postV1Tests":{"type":"object","properties":{"test":{"type":"object","description":"Test attributes.","properties":{"name":{"type":"string","description":"Test name."},"success":{"type":"boolean","description":"true=pass, false=fail."},"status_message":{"type":"string","description":"Failure reason or status string."},"extra":{"type":"string","description":"Arbitrary metadata."},"build":{"type":"string","description":"Build identifier."}},"required":["name"]}},"required":["test"],"description":"Create a test record (manual sessions)"},"Testingbot_Entities_User":{"type":"object","properties":{"first_name":{"type":"string","description":"Given name on the account."},"last_name":{"type":"string","description":"Family name on the account."},"email":{"type":"string","description":"Account email address."},"plan":{"type":"string","description":"Subscription plan identifier (e.g. \"live\", \"automated\", \"automated pro\")."},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of parallel VM-based sessions allowed by the plan."},"max_concurrent_mobile":{"type":"integer","format":"int32","description":"Maximum number of parallel physical device sessions allowed by the plan."},"seconds":{"type":"integer","format":"int32","description":"Remaining test seconds (credit balance) on the account."},"last_login":{"type":"string","format":"date-time","description":"ISO-8601 timestamp of the most recent dashboard login."},"company":{"type":"string","description":"Optional company name for billing."},"street":{"type":"string","description":"Billing address line."},"city":{"type":"string","description":"Billing city."},"country":{"type":"string","description":"Billing country."},"vat":{"type":"string","description":"VAT number (EU only)."}},"required":["first_name","last_name","email","plan","max_concurrent","max_concurrent_mobile","seconds","last_login","company","street","city","country","vat"],"description":"Testingbot_Entities_User model"},"putV1User":{"type":"object","properties":{"user":{"type":"object","description":"User attributes to update.","properties":{"first_name":{"type":"string","description":"New given name."},"last_name":{"type":"string","description":"New family name."}}}},"required":["user"],"description":"Update your user info"},"Testingbot_Entities_UserUpdate":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the update was applied."},"user":{"allOf":[{"$ref":"#/definitions/Testingbot_Entities_User"}],"description":"Updated user object."}},"required":["success","user"],"description":"Testingbot_Entities_UserUpdate model"}}}