TestingBot API Documentation
Access and modify all your TestingBot data through our comprehensive REST API. Build powerful integrations and automate your testing workflows.
- Endpoint
- api.testingbot.com
- Version
- v1
- Format
- JSON
- Auth
- HTTP Basic
API Reference
The reference is split by resource. Every endpoint below is authenticated with the API key and secret described in Authentication.
- Browsers & Devices 5 endpoints Discover which browsers, operating systems and real devices you can run on, and look up the IP ranges to allowlist.
- User & Team Management 16 endpoints Your own account and credentials, plus everything needed to provision team members and service accounts from a script.
- Tests & Builds 12 endpoints Fetch test results, report pass/fail state back from your CI, and work with the builds that group them.
- Insights 5 endpoints The data behind the Test Analytics dashboard, exposed so you can build your own reporting.
- Screenshots 3 endpoints Kick off a screenshot run across browsers and fetch the images when it finishes.
- Tunnel 7 endpoints Manage the secure tunnels that let the grid reach your staging and internal environments.
- Codeless Automation & TestLab 29 endpoints Drive the codeless test builder and the TestLab suites that group those tests, end to end.
- TestingBot Storage 5 endpoints Upload app binaries and test bundles once, then reference them from your capabilities with a tb:// URL.
- Webhooks 7 endpoints Manage the callbacks TestingBot posts when a test finishes, and verify them without waiting for a run.
- App Automate 33 endpoints Everything for native mobile test runs: Maestro flows, Espresso and XCUITest suites, and their reports.
API Clients
There are several open source client libraries available to easily interact with the TestingBot API:
Authentication
Every TestingBot API request is authenticated with your API key and API secret using HTTP Basic Auth over HTTPS. The only unauthenticated endpoint is GET /v1/browsers.
1 · Find your credentials
Sign in to TestingBot and open Account → Account Info. You'll find:
-
keystring - Your public API client key. Safe to share between your CI and the TestingBot grid; not a secret on its own.
-
secretstring sensitive - Treat this like a password. Never commit it to git, never paste it into screenshots, never embed it in client-side code. Use environment variables or a secret manager in CI.
2 · Send credentials on every request
Pass the credentials as the standard Authorization header. Most HTTP clients accept a user:password tuple and handle the Base64 encoding for you — examples on the right.
3 · Verify it works
Hit GET /v1/user. A JSON response with your name and plan means auth is set up correctly. A 401 Unauthorized means the key or secret is wrong.
TESTINGBOT_KEY and TESTINGBOT_SECRET — and inject them into your CI/CD pipeline as secrets. Rotate the secret immediately if it leaks (Account → Reset API credentials).
$ curl https://api.testingbot.com/v1/user \
-u "$TESTINGBOT_KEY:$TESTINGBOT_SECRET"
using TestingBot.Api;
// reads TESTINGBOT_KEY / TESTINGBOT_SECRET from the environment
using var client = TestingBotClient.FromEnvironment();
var user = await client.User.GetAsync();
require 'testingbot'
api = TestingBot::Api.new(
ENV['TESTINGBOT_KEY'],
ENV['TESTINGBOT_SECRET']
)
api.get_user_info
import os, testingbotclient
tb = testingbotclient.TestingBotClient(
os.environ['TESTINGBOT_KEY'],
os.environ['TESTINGBOT_SECRET']
)
tb.user.get_user_information()
$api = new TestingBot\TestingBotAPI(
getenv('TESTINGBOT_KEY'),
getenv('TESTINGBOT_SECRET')
);
$api->getUserInfo();
TestingbotREST restApi = new TestingbotREST(
System.getenv("TESTINGBOT_KEY"),
System.getenv("TESTINGBOT_SECRET")
);
TestingbotUser user = restApi.getUserInfo();
const TestingBot = require('testingbot-api');
const api = new TestingBot({
api_key: process.env.TESTINGBOT_KEY,
api_secret: process.env.TESTINGBOT_SECRET
});
const userInfo = await api.getUserInfo();
Reducing response size
Any endpoint accepts an optional omit query parameter to drop fields you don't need from the JSON response. Pass a comma-separated list of field names. This is handy for trimming large payloads, for example skipping the embedded report and report_xml on App Automate run details.
-
omitstring - Comma-separated field names to exclude. Matching is by field name and applies anywhere it appears in the response, including inside
datalist items and nested objects. Unknown names are ignored.
omit never affects whether a request succeeds, only the shape of the body. Omitting nothing returns the full, default response.
$ curl "https://api.testingbot.com/v1/app-automate/maestro/12/45?omit=report,report_xml" \
-u "$TESTINGBOT_KEY:$TESTINGBOT_SECRET"
{
"id": 45,
"status": "DONE",
"success": true,
"created_at": "2026-06-01T10:00:00.000Z"
}
Rate limits
Requests are counted in a rolling five-minute window. Authenticated requests count against your API key, so one busy CI job cannot spend a colleague's budget, and a key that leaks is capped rather than free.
-
2000 requests / 5 minutesper API key - Roughly 6 requests per second sustained. Applies to every authenticated endpoint.
-
300 requests / 5 minutesper IP - For requests sent without credentials, which can only reach the public endpoints such as GET /v1/browsers.
Every tunnel endpoint is exempt. Tunnels are infrastructure rather than a data surface: the client polls while a tunnel boots, and the tunnel VM itself reports readiness, so a limit there would stall provisioning rather than stop abuse.
Sending a test webhook delivery has its own, much tighter allowance of 20 per 5 minutes per API key, on top of the limit above. Each call makes TestingBot perform an outbound request to a URL you choose, and verifying a webhook is a setup-time action rather than something to do in bulk.
Every API response carries your current usage, so you can slow down before you are cut off rather than after:
-
X-RateLimit-Limitinteger - Requests allowed in the current window.
-
X-RateLimit-Remaininginteger - Requests left in the current window.
-
X-RateLimit-Resetinteger - UNIX timestamp at which the window resets and the allowance returns to full.
429 Too Many Requests with a Retry-After header giving the seconds to wait. The body is JSON in the usual shape, so an SDK surfaces it as an API error rather than a parse failure. Retrying after Retry-After is always safe.
X-RateLimit-Limit: 2000
X-RateLimit-Remaining: 1994
X-RateLimit-Reset: 1785736800
{
"error": "429 Too Many Requests. Retry in 300 seconds."
}