Skip to main content

Legacy API (v1 Compatibility)

If you are migrating from TestFairy, your existing CI/CD scripts and plugins will continue to work without changes. The legacy API endpoints are fully supported alongside the new API v3.

Authentication​

All endpoints require authentication. You can authenticate using any of the following methods:

MethodExample
X-API-Key headercurl -H "X-API-Key: YOUR_KEY" ...
api_key POST paramcurl -F api_key=YOUR_KEY ...

Response Format​

All responses return JSON with a status field ("ok" or "fail").

Success

{ "status": "ok", ... }

Error

{ "status": "fail", "code": 5, "message": "..." }

Upload​

POST /api/upload​

Upload an APK, AAB, or IPA file. The app is automatically matched by package name, or created if it doesn't exist.

curl https://app.testfairy.com/api/upload \
-F api_key=YOUR_API_KEY \
-F file=@app-release.apk \
-F changelog="Bug fixes and improvements" \
-F notify=on \
-F groups="QA,Beta"
ParameterRequiredDescription
fileYesBinary file (.apk, .aab, or .ipa)
changelogNoRelease notes. Also accepted as comment or release_notes
notifyNoSet to on or 1 to email testers about the new build
groupsNoComma-separated tester group names or IDs to grant the app to. Combine with notify=on to email them
app_versionNoOverride the auto-detected version string
version_codeNoOverride the auto-detected version code
folder_nameNoAssign the app to a folder

Projects​

GET /api/1/projects/​

List all apps in the organization.

curl -H "X-API-Key: YOUR_KEY" https://app.testfairy.com/api/1/projects/

Response includes: id, self, name, folderName, packageName, platform, icon, landingPageMode.

Builds​

GET /api/1/projects/{projectId}/builds/​

List all builds for an app.

GET /api/1/projects/{projectId}/builds/{buildId}​

Get a single build.

Response includes: id, projectId, appName, appDisplayName, appVersion, appVersionCode, iconUrl, appUrl, platform, comment, tags, downloads, uploadedAt, uploadedVia, isDistributionEnabled.

PATCH /api/1/projects/{projectId}/builds/{buildId}/​

Update a build's metadata.

ParameterDescription
commentUpdate release notes
tagsComma-separated tags

DELETE /api/1/projects/{projectId}/builds/{buildId}​

Delete a build. Requires admin permissions.

GET /api/1/projects/{projectId}/builds/{buildId}/download/​

Download a build. Responds with an HTTP 302 redirect to a pre-signed download URL (or to the install page when file storage isn't configured), so follow redirects, for example with curl -L.

POST /api/1/projects/{projectId}/builds/{buildId}/invites/​

Send install invitations to testers for a build.

Testers​

GET /api/1/testers​

List all testers in the organization.

Response includes: id, email, invitationStatus, isBlocked, groups, lastLogin, createdAt, plus hasUdidAccess, allowAll, hasPushToken, emailBounce, onlyAccount, account, allDevices, appleDevices.

POST /api/1/testers/​

Add a tester. Creates the user if they don't exist. Requires admin permissions.

ParameterRequiredDescription
emailYesTester's email address
groupNoGroup name to add the tester to

GET /api/1/testers/{testerId}​

Get a single tester's details.

DELETE /api/1/testers/{testerId}​

Remove a tester from the organization. Requires admin permissions.

POST /api/1/testers/{testerId}/block/​

Block a tester. Requires admin permissions.

DELETE /api/1/testers/{testerId}/block/​

Unblock a tester. Requires admin permissions.

Tester Groups​

GET /api/1/testers/groups​

List all tester groups. Response includes: id, name, testers (a nested list of { "email" } objects).

POST /api/1/testers/groups​

Create a tester group. Requires admin permissions.

ParameterRequiredDescription
groupNameYesName for the new group

POST /api/1/testers/groups/{groupId}​

Add an existing tester to a group by email. If the email doesn't belong to a tester in your organization, the call returns { "status": "ok", "testers": [] } and nothing changes. Requires admin permissions.

ParameterRequiredDescription
emailYesTester's email address

DELETE /api/1/testers/groups/{groupId}​

Remove a tester from a group by email. Requires admin permissions.

ParameterRequiredDescription
emailYesTester's email address (POST body or query param)

Groups​

GET /api/1/groups/​

List all groups in the organization. Response includes: id, name, private.

GET /api/1/groups/{groupId}​

Get a single group.

GET /api/1/groups/{groupId}/testers/​

List all testers in a group. Each entry contains email only. Paginated with page and per_page (default 50, max 200).

GET /api/1/groups/{groupId}/projects/​

List all apps assigned to a group. Response includes: id, name. Paginated with page and per_page (default 25, max 100).

Webhooks​

GET /api/1/webhooks/​

List all webhooks for the organization.

Response includes: id, name, url, status, actions (comma-separated), projectIds (comma-separated, or * for all apps).

POST /api/1/webhooks/​

Create a webhook. Requires admin permissions.

ParameterRequiredDescription
urlYesWebhook callback URL
nameYesDisplay name. Also accepted as webhook-name. Missing name returns code 104
actionsNoComma-separated event types to listen for
project_idsNoComma-separated app IDs (empty = all apps)

GET /api/1/webhooks/{webhookId}​

Get a single webhook.

POST /api/1/webhooks/{webhookId}​

Update a webhook. Requires admin permissions. Accepts the same parameters as create (all optional).

DELETE /api/1/webhooks/{webhookId}​

Delete a webhook. Requires admin permissions.

Sites (Teams)​

In the legacy API, "sites" correspond to "teams" in the current platform.

GET /api/1/sites/​

List all sites (teams) in the organization.

Response is { "site": { "accounts": [...], "managers": [...] } }. Each account includes id, name, buildsCount and users (each with email and role); each manager includes email. Only the account owner or an org admin can call this endpoint; other roles receive { "status": "fail", "code": 1, "message": "Feature is not enabled" } with HTTP 200.

GET /api/1/sites/{siteId}​

Get a single site (team).

POST /api/1/sites/​

Create a site (team). Requires admin permissions.

ParameterRequiredDescription
nameYesSite (team) name

Audit Logs​

Requires admin permissions. GET /api/1/audits/ ignores query parameters and always returns up to 1000 app-download events. The /api/2 audit endpoints support the following query parameters:

ParameterDescription
pagePage number (default: 1)
limitResults per page (default: 50, max: 100). per_page is also accepted and takes precedence
actionFilter by action type
searchSearch in email and action data
fromStart date (ISO 8601)
toEnd date (ISO 8601)

GET /api/1/audits/​

List audit log entries.

GET /api/2/audits/​

List audit log entries (v2 format with pagination metadata).

GET /api/2/audits/admin-trail/​

List admin activity audit trail.

GET /api/2/audits/tester-trail/​

List tester activity audit trail.

Response includes: id, timestamp, enterpriseId, siteName, userId, userEmail, ipAddress, actionType, actionLabel, actionData, plus pagination object.

Error Codes​

CodeHTTP StatusMeaning
1400Missing or invalid required parameter
2400Duplicate resource (already exists)
5401/403API key valid but no organization membership (401), or admin permissions required (403). On /api/upload, an invalid key also returns code 5 with HTTP 200
104401Missing or invalid API key (/api/1 and /api/2 endpoints)
112400Empty file uploaded
121400Invalid file type
133400Organization not configured (no team found)
400200Tester not found (for example, Invalid Tester)
404200Group not found

CI/CD Examples​

Gradle (Android)

curl https://app.testfairy.com/api/upload \
-F api_key=$API_KEY \
-F file=@app/build/outputs/apk/release/app-release.apk \
-F changelog="$(git log -1 --pretty=%B)"

Xcode (iOS)

curl https://app.testfairy.com/api/upload \
-F api_key=$API_KEY \
-F file=@build/MyApp.ipa \
-F changelog="$(git log -1 --pretty=%B)" \
-F notify=on

List apps and builds

# List apps
curl -H "X-API-Key: $API_KEY" https://app.testfairy.com/api/1/projects/

# List builds for an app
curl -H "X-API-Key: $API_KEY" https://app.testfairy.com/api/1/projects/123/builds/

# Get download URL
curl -H "X-API-Key: $API_KEY" https://app.testfairy.com/api/1/projects/123/builds/456/download/

Migration to API v3​

To migrate, see the API Migration Guide.