DOCS
Reference

API: App builds

App builds: List builds, Get a build, Start a build upload, Upload a build part, Complete a build upload, Delete a build.

List builds

GET/api/v1/projects/{projectId}/builds

The app builds uploaded to a project (Android .apk, iOS Simulator .app zipped), newest first, with the largest size and part size for uploads.

MCP tool: list_builds. Works with any key.

Path
projectIdstringrequired
Project id (p_…)

Returns { builds: [{ id, status, fileName, size, platform, appId, appName, version, versionCode, minOs, abis, warnings, label, createdAt, readyAt }], maxBytes, partBytes }

Request
curl https://app.testsy.dev/api/v1/projects/p_8f2k/builds \
  -H "Authorization: Bearer $QA_AI_API_KEY"

Get a build

GET/api/v1/builds/{buildId}

One build: its app id, version, status and any warnings.

MCP tool: get_build. Works with any key.

Path
buildIdstringrequired
Build id (ab_…)

Returns { build: { id, projectId, status, fileName, size, platform, appId, appName, version, versionCode, minOs, abis, warnings, sha256, label, createdAt, readyAt } }

Request
curl https://app.testsy.dev/api/v1/builds/ab_q3 \
  -H "Authorization: Bearer $QA_AI_API_KEY"

Start a build upload

POST/api/v1/projects/{projectId}/builds

Start uploading a build: returns its id, the part size and the number of parts. The command-line tool does all three steps: qa-ai build upload.

REST only. Works with any key, including one that can only run tests and read results.

Path
projectIdstringrequired
Project id (p_…)
Body (JSON)
fileNamestringrequired
app.apk or MyApp.app.zip
sizenumberrequired
Size in bytes
labelstring
A label, for example the commit (optional)

Returns 201 { id, partBytes, parts }

Request
curl -X POST https://app.testsy.dev/api/v1/projects/p_8f2k/builds \
  -H "Authorization: Bearer $QA_AI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileName":"app-debug.apk","size":41943040}'

Upload a build part

PUT/api/v1/builds/{buildId}/parts/{partNumber}

Upload one part: the raw bytes as the body (partBytes each, the last one shorter). Returns its etag.

REST only. Works with any key, including one that can only run tests and read results.

Path
buildIdstringrequired
Build id (ab_…)
partNumberstringrequired
1, 2, 3 …

Returns { partNumber, etag }

Request
curl -X PUT https://app.testsy.dev/api/v1/builds/ab_q3/parts/1 \
  -H "Authorization: Bearer $QA_AI_API_KEY" \
  --data-binary @part-1.bin

Complete a build upload

POST/api/v1/builds/{buildId}/complete

Finish the upload with every part's etag. The build is checked (app id, version, whether our devices can run it) and returned.

REST only. Works with any key, including one that can only run tests and read results.

Path
buildIdstringrequired
Build id (ab_…)
Body (JSON)
partsobject[]required
[{partNumber, etag}]

Returns { build }: the checked build, or 422 build_rejected with what our devices cannot run

Request
curl -X POST https://app.testsy.dev/api/v1/builds/ab_q3/complete \
  -H "Authorization: Bearer $QA_AI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"parts":[{"partNumber":1,"etag":"…"}]}'

Delete a build

DELETE/api/v1/builds/{buildId}

Delete a build. Runs that used it keep their results; a build a test pins cannot be deleted.

MCP tool: delete_build. Needs a key that can also create and edit tests.

Path
buildIdstringrequired
Build id (ab_…)

Returns { ok: true }

Request
curl -X DELETE https://app.testsy.dev/api/v1/builds/ab_q3 \
  -H "Authorization: Bearer $QA_AI_API_KEY"