REST API
In this document you can find the reference for the Sauce Labs Mobile App Distribution REST API. This API allows the developer to access and interact with Sauce Labs Mobile App Distribution data remotely.
Authentication
The REST API supports two authentication methods:
| Method | Documentation |
|---|---|
| API Key | API Keys |
| OIDC | OIDC Authentication |
API Key (HTTP Basic Auth)
curl -u "email:api-key" "https://mobile.saucelabs.com/api/1/projects/"
OIDC (Bearer Token)
curl -X GET "https://mobile.saucelabs.com/api/1/projects/" \
-H "Authorization: Bearer <your-access-token>" \
-H "X-OIDC-Config-Key: <your-config-key>"
See OIDC Authentication: API Usage for setup and token retrieval.
For CI/CD automation, use service accounts.
API Endpoints
Sauce Labs Mobile App Distribution REST API is available at the following endpoints:
US-East-1 (Primary)
https://mobile.saucelabs.com/api/1/
EU-Central-1
https://mobile.eu-central-1.saucelabs.com/api/1/
Access keys are different in each Data Center. Ensure you are using the correct API key for the data center you are accessing.
Legacy Endpoint (US-East)
The previous TestFairy endpoint remains available:
https://api.testfairy.com/api/1/
Getting Started
Getting started with the REST API can be done via the command line with any programming language. Let's begin with an example: by listing all our projects.
Example: List All Projects
US-East-1:
curl -u "john@example.com:00001234cafecafe" "https://mobile.saucelabs.com/api/1/projects/"
EU-Central-1:
curl -u "john@example.com:coffee00001234" "https://mobile.eu-central-1.saucelabs.com/api/1/projects/"
A project is either an iOS app or an Android app (two apps with the same package name but on different platforms are considered two projects.)
In the example above, the user is john@example.com and the API key is 0001234cafecafe. This authentication is required for all requests to the REST server.
Projects
Get All Projects
GET/api/1/projects/
Responses
200 | Success. | |
{
"status": "ok",
"projects": [
{
"id": "6905338",
"self": "/projects/19-groupshot",
"name":"GroupShot",
"packageName":"com.groupshot",
"platform":"Android",
"icon":"[URL TO APP ICON]",
"landingPageMode": "open"
}
]
}
Builds
Get All Builds in a Project
GET/api/1/projects/{project-id}/builds/
Responses
200 | Success. | |
{
"status": "ok",
"builds": [
{
"id":"8830728",
"self":"/projects/6806100-myapplication/builds/8830728",
"projectId":"6806100",
"appName":"My Application",
"appVersion":"DemoApp",
"appVersionCode":"20",
"appDisplayName":"My Application - DemoApp (20)",
"iconUrl":"[APP ICON URL]",
"appUrl":"[URL TO APK OR IPA FILE]",
"landingPageMode": "closed",
"sessions":6,
"crashes":0,
"testers":0,
"feedbacks":0,
"downloads":1,
"uploadedAt":"2019-04-04 16:03:15",
"uploadedVia":"[UPLOAD DETAILS]",
"hasTestFairySdk":true,
"insightsEnabled":true,
"videoEnabled":true
}
]
}
Get Metadata for a Specific Build
GET/api/1/projects/{project-id}/builds/{build-id}
Responses
200 | Success. | |
{
"status": "ok",
"build": {
"id":"8830728",
"self":"/projects/6806100-myapplication/builds/8830728",
"projectId":"6806100",
"appName":"My Application",
"appVersion":"DemoApp",
"appVersionCode":"20",
"appDisplayName":"My Application - DemoApp (20)",
"iconUrl":"[APP ICON URL]",
"appUrl":"[URL TO APK OR IPA FILE]",
"landingPageMode": "closed",
"sessions":6,
"crashes":0,
"testers":0,
"feedbacks":0,
"downloads":1,
"uploadedAt":"2019-04-04 16:03:15",
"uploadedVia":"[UPLOAD DETAILS]",
"hasTestFairySdk":true,
"insightsEnabled":true,
"videoEnabled":true
}
}
Delete a Specific Build
DELETE/api/1/projects/{project-id}/builds/{build-id}
Responses
200 | Success. | |
{
"status": "ok"
}
Update a Specific Build
PATCH/api/1/projects/{project-id}/builds/{build-id}/
application/x-www-form-urlencoded or application/json. Note: multipart/form-data is not supported for this endpoint.Parameters
comment | | OPTIONAL | STRING | Release notes / changelog for the build. Also accepted as |
tags | | OPTIONAL | STRING | Comma-separated list of tags. |
groups or app_permission_groups | | OPTIONAL | STRING | Comma-separated list of tester group names. If present but empty, clears all groups. If omitted, groups are unchanged. |
landing_page_mode | | OPTIONAL | STRING | Landing page mode: |
metadata_* | | OPTIONAL | STRING | Custom metadata fields. Use the prefix |
Responses
200 | Success. | |
curl -X PATCH \
"https://mobile.saucelabs.com/api/1/projects/{project-id}/builds/{build-id}/" \
-u "john@example.com:00001234cafecafe" \
-d "comment=New release notes" \
-d "tags=production,v2" \
-d "groups=beta-testers,qa" \
-d "landing_page_mode=open" \
-d "metadata_title=My App Title"
{
"status": "ok",
"build_id": "8830728",
"tags": ["production", "v2"],
"metadata": {
"title": "My App Title"
},
"changelog": "New release notes",
"groups": ["beta-testers", "qa"],
"landing_page_mode": "open"
}
Error Codes
1 | Missing or invalid build-id. | |
99 | No permissions — the authenticated user does not have write access to this project. | |
133 | Tester accounts cannot update builds. | |
156 | Cannot set landing_page_mode to open when login is required by the account settings. | |
Copy a Specific Build to a Folder
POST/api/1/projects/{project-id}/builds/{build-id}/copy
Parameters
folder_name | | REQUIRED | STRING | The name or path of the target folder. Examples: Folder1 or /Project1/Folder1. |
app_name | | OPTIONAL | STRING | Defines a new name for the application when copying the build to the target folder. |
groups | | OPTIONAL | STRING | A comma-separated list of tester group names or IDs for the build. |
projectGroups | | OPTIONAL | STRING | A comma-separated list of tester group names or IDs for the project. |
allowAllTesters | | OPTIONAL | BOOLEAN | Value |
Responses
200 | Success. | |
{
"status": "ok",
"build_id": "1000",
"folder_path": "/Project1/Folder1",
"app_name": "My Application",
"assigned_groups": [
"13",
"group14",
"12"
],
"invalid_groups": [
"abcd",
"efgd"
],
"assigned_project_groups": [
"group13",
"14",
"12"
],
"invalid_project_groups": [
"abcd",
"efgd"
]
}
Download the Uploaded Artifact
GET/api/1/projects/{project-id}/builds/{build-id}/download/
Responses
200 | Success. | |
Invite Additional Testers to Build
POST/api/1/projects/{project-id}/builds/{build-id}/invites/
Parameters
groups | | REQUIRED | STRING | A comma-separated list of tester group names or IDs. |
comment | | OPTIONAL | STRING | Additional text that will be added to the email, such as release notes. |
notify | | OPTIONAL | STRING | INTEGER Pass |
Responses
200 | Success. | |
Testers
List All Testers
GET/api/1/testers
Query Parameters
buildId | | OPTIONAL | INTEGER | When provided, each tester includes build-specific fields: |
Responses
200 | Success. | |
{
"status": "ok",
"testers": [
{
"email": "james@example.com",
"groups": [{
"id": 100,
"name": "friends"
}],
"lastLogin": "2025-11-20 14:30:00",
"createdAt": "2024-06-15 09:00:00"
},
{
"email": "alice@testfairy.com",
"groups": [{
"id": 100,
"name": "friends"
}, {
"id": 200,
"name": "family"
}],
"lastLogin": "2026-01-10 08:45:00",
"createdAt": "2024-03-22 11:30:00"
}
]
}
Add a New Tester
POST/api/1/testers/
Parameters
email | | OPTIONAL | STRING | One or more emails, separated by commas, to add to your account. |
group | | OPTIONAL | STRING | Assign tester or testers to this tester-group. It creates one if no such group exists. Default value: none. |
notify | | OPTIONAL | STRING | INTEGER Pass |
Responses
200 | Success. | |
{
"status": "ok"
}
Get a Single Tester
GET/api/1/testers/{tester-id}
Responses
200 | Success. | |
{
"status": "ok",
"tester": {
"id": 123,
"email": "james@example.com",
"isBlocked": false,
"groups": [{
"id": 100,
"name": "friends"
}],
"lastLogin": "2025-11-20 14:30:00",
"createdAt": "2024-06-15 09:00:00"
}
}
Block a Tester
POST/api/1/testers/{tester-id}/block/
Responses
200 | Success. | |
{
"status": "ok"
}
Unblock a Tester
DELETE/api/1/testers/{tester-id}/block/
Responses
200 | Success. | |
{
"status": "ok"
}
Delete a Tester
DELETE/api/1/testers/{tester-id}
Responses
200 | Success. | |
{
"status": "ok"
}
Add a Tester to a Group
POST/api/1/testers/groups/{group-id}
Parameters
email | | REQUIRED | STRING | One or more email addresses, separated by commas, to be added to a group. |
Responses
200 | Success. | |
{
"status": "ok",
"testers": [
{
"email": "tester1@saucelabs.com"
},
{
"email": "tester2@saucelabs.com"
}
]
}
Remove a Tester from a Group
DELETE/api/1/testers/groups/{group-id}
Parameters
email | | REQUIRED | STRING | One or more email addresses, separated by commas, to be removed from a group. |
Responses
200 | Success. | |
{
"status": "ok",
"testers": [
{
"email": "tester1@saucelabs.com"
},
{
"email": "tester2@saucelabs.com"
}
]
}
List All Tester groups
GET/api/1/testers/groups
Responses
200 | Success. | |
{
"status": "ok",
"groups": [
{
"id": 14,
"name": "group1",
"testers": [
[
{
"email": "tester1@saucelabs.com"
},
{
"email": "tester2@saucelabs.com"
},
{
"email": "tester3@saucelabs.com"
}
]
]
},
{
"id": 39,
"name": "group2",
"testers": [
[
{
"email": "tester1@saucelabs.com"
}
]
]
}
]
}
Create a Tester Group
POST/api/1/testers/groups
Feedbacks
Get Latest Recorded Feedbacks
GET/api/1/feedbacks/
Responses
200 | Success. | |
{
"status": "ok",
"feedbacks": [
{
"recorded_at": "2018-08-01 04:14:46",
"text": "Feedback working",
"feedbackId": "54321",
"screenshotUrl": "https://s3.amazonaws.com/feedback.jpg",
"buildId": "1234",
"projectId": "23456",
"recordedAt":"2018-08-01 14:14:46",
"source": "shake",
"reported_by": "john@testfairy.com",
"session_id": "8765432"
}
]
}
Audits
Get Recent Audit Trail Items (Deprecated)
This endpoint is deprecated. Use the v2 audit endpoints below instead: /api/2/audits/, /api/2/audits/admin-trail/, /api/2/audits/tester-trail/.
GET/api/1/audits
Responses
200 | Success. | |
{
"status": "ok",
"audits": [
{
"id": 23534603,
"timestamp": "2020-04-21 02:31:54",
"ipAddress": "54.235.41.91",
"eventType": "download_app",
"eventData": {
"projectId": 6833287,
"buildId": 9087976,
"appName": "MyApp",
"appVersion": "1.0 (10)",
"testerEmail": "john@example.com",
"filesize": 31348
}
}
]
}
Get All Audit Logs
GET/api/2/audits/
Query Parameters
site | string or int | Optional. Multi-site accounts only. Filter by site subdomain (e.g. site-1) or enterprise ID (e.g. 456). Must be within the caller's accessible sites. |
action_type | int | Optional. Filter by a specific action type ID. |
start_date | string | Optional. Filter from date (format: YYYY-MM-DD). |
end_date | string | Optional. Filter to date (format: YYYY-MM-DD). |
page | int | Page number (default: 1). |
per_page | int | Results per page (default: 50, max: 200). |
Responses
200 | Success. | |
{
"status": "ok",
"audits": [
{
"id": 789,
"timestamp": "2026-03-01 09:00:00",
"enterpriseId": 456,
"siteName": "My Organization",
"userId": 789,
"userEmail": "admin@example.com",
"ipAddress": "1.2.3.4",
"actionType": 1905,
"actionLabel": "Security settings changed",
"actionData": {
"from": {"mfa_enabled": false},
"to": {"mfa_enabled": true}
}
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 315,
"total_pages": 7
}
}
Get Admin Trail Audit Logs
GET/api/2/audits/admin-trail/
Query Parameters
site | string or int | Optional. Multi-site accounts only. Filter by site subdomain (e.g. site-1) or enterprise ID (e.g. 456). Must be within the caller's accessible sites. |
action_type | int | Optional. Filter by a specific action type ID. |
start_date | string | Optional. Filter from date (format: YYYY-MM-DD). |
end_date | string | Optional. Filter to date (format: YYYY-MM-DD). |
page | int | Page number (default: 1). |
per_page | int | Results per page (default: 50, max: 200). |
Responses
200 | Success. | |
{
"status": "ok",
"audits": [
{
"id": 123,
"timestamp": "2026-02-25 10:30:00",
"enterpriseId": 456,
"siteName": "My Organization",
"userId": 789,
"userEmail": "admin@example.com",
"ipAddress": "1.2.3.4",
"actionType": 1905,
"actionLabel": "Security settings changed",
"actionData": {
"from": {"mfa_enabled": false},
"to": {"mfa_enabled": true}
}
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 230,
"total_pages": 5
}
}
Get Tester Trail Audit Logs
GET/api/2/audits/tester-trail/
Query Parameters
site | string or int | Optional. Multi-site accounts only. Filter by site subdomain (e.g. site-1) or enterprise ID (e.g. 456). Must be within the caller's accessible sites. |
action_type | int | Optional. Filter by a specific action type ID. |
start_date | string | Optional. Filter from date (format: YYYY-MM-DD). |
end_date | string | Optional. Filter to date (format: YYYY-MM-DD). |
page | int | Page number (default: 1). |
per_page | int | Results per page (default: 50, max: 200). |
Responses
200 | Success. | |
{
"status": "ok",
"audits": [
{
"id": 456,
"timestamp": "2026-02-25 14:15:00",
"enterpriseId": 456,
"siteName": "My Organization",
"userId": 789,
"userEmail": "admin@example.com",
"ipAddress": "1.2.3.4",
"actionType": 1200,
"actionLabel": "Invited testers",
"actionData": {
"emails": ["tester1@example.com", "tester2@example.com"]
}
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 85,
"total_pages": 2
}
}
Permissions
Get the List of Admins and Their Permissions
GET/api/1/cpanel/permissions/
Responses
200 | Success. | |
{
"status": "ok",
admins:
[
{
email: "joe@example.com",
role: "account-owner",
permissions: [
"*:rw"
]
},
{
email: "bob@example.com",
role: "account-manager",
permissions: [
"*:rw"
]
},
{
email: "alice@example.com",
role: "admin",
permissions: [
"*:rw"
]
},
{
email: "michael@example.com",
role: "admin",
permissions: [
"16527:rw",
"16517:rw",
"69237:r"
]
},
]
}
Webhooks
List All Webhooks
GET/api/1/webhooks/
Responses
200 | Success. | |
{
"status":"ok",
"webhooks":[
{
"id":12,
"status":"0",
"name":"Slack Webhook @vijay",
"url":"https://hooks.slack.com/services/",
"actions":"crash,feedback,upload,new-udid",
"projectIds":"12345,45643"
}
]
}
Add a New Webhook
POST/api/1/webhook/
Parameters
webhook-name | | REQUIRED | STRING | The name of the webhook. |
webhook-url | | REQUIRED | STRING | The URL for the webhook. |
webhook-status | | OPTIONAL | STRING | Enables or disables the webhook. The values are: |
actions | | OPTIONAL | STRING | Comma separated list of actions. Options include: |
webhook-project-ids | | OPTIONAL | STRING | Comma separated list of project IDs. |
Responses
200 | Success. | |
{
"status": "ok"
}
Get a Single Webhook
GET/api/1/webhook/{webhook-id}/
Responses
200 | Success. | |
{
"status": "ok",
"webhook": {
"id":12,
"status":"0",
"name":"Slack Webhook @vijay",
"url":"https://hooks.slack.com/services/",
"actions":"crash,feedback,upload,new-udid",
"projectIds":"12345,45643"
}
}
Modify a Webhook
POST/api/1/webhook/{webhook-id}/
Parameters
webhook-name | | REQUIRED | STRING | The name of the webhook. |
webhook-url | | REQUIRED | STRING | The URL for the webhook. |
webhook-status | | OPTIONAL | STRING | Enables or disables the webhook. The values are: |
actions | | OPTIONAL | STRING | Comma separated list of actions. Options include: |
webhook-project-ids | | OPTIONAL | STRING | Comma separated list of project IDs. |
Responses
200 | Success. | |
{
"status": "ok"
}
Delete a Webhook
DELETE/api/1/webhook/{webhook-id}/
Sites
List All Sites
GET/api/1/site/
Responses
200 | Success. | |
{
"status": "ok",
"site": {
"accounts": [
{
"id": "1",
"name": "Site 1",
"buildsCount": 0,
"users": [
{
"email": "[site-subaccount-682ae46476f9f]",
"role": "Account Owner"
},
{
"email": "sitemanager@saucelabs.com",
"role": "Account Manager"
}
]
}
],
"managers": [
{
"email": "accountmanager@saucelabs.com"
}
]
}
}
Create a New Site
POST/api/1/site/
Parameters
name | | REQUIRED | STRING | The name of the account. The string accepts numbers, letters, |
loginMethod | | OPTIONAL | STRING | Specify how users can log in to account. Pass |
Responses
200 | Success. | |
{
"status": "ok"
}