> For the complete documentation index, see [llms.txt](https://docs.drizz.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.drizz.dev/automate-and-integrate/api-overview.md).

# API Overview

The Drizz REST API covers three operations: authenticate, upload a build, trigger a test plan.

In the examples below, the shell variable `DRIZZ_BASE_URL` holds that value, and `DRIZZ_API_KEY` holds the access token returned by the auth call.

{% hint style="info" %}
**At a glance**

`POST <DRIZZ_API_BASE_URL>/testplan/run`
{% endhint %}

|                |                                                                                    |
| -------------- | ---------------------------------------------------------------------------------- |
| **Auth**       | OAuth 2.0 client credentials → a bearer token, sent as `x-api-key`                 |
| **Token life** | 24 hours (`expires_in: 86400`)                                                     |
| **Rate limit** | \~4 requests/second, burst \~20, per client → HTTP 429 over that                   |
| **Upload cap** | 500 MB per binary                                                                  |
| **Watch out**  | There is no endpoint to poll a run or fetch results. Trigger is where the API ends |

## Prerequisites

* Active Drizz organization account
* Client ID and client secret, issued by Drizz
* Auth host and audience string, issued by Drizz
* API base URL for your organization
* At least one registered app, with its package name or bundle ID
* At least one test plan, with its ID
* `curl` and `jq`, or an equivalent HTTP client

## Copy this

```bash
# 1 — set these once
export DRIZZ_BASE_URL="<DRIZZ_API_BASE_URL>"
export DRIZZ_AUTH_DOMAIN="<auth-domain>"
export DRIZZ_CLIENT_ID="<your_client_id>"
export DRIZZ_CLIENT_SECRET="<your_client_secret>"
export DRIZZ_AUDIENCE="<DRIZZ_API_AUDIENCE>"

# 2 — authenticate. The token is valid for 24 hours
export DRIZZ_API_KEY=$(curl -s -X POST "https://${DRIZZ_AUTH_DOMAIN}/oauth/token" \
  -H "Content-Type: application/json" \
  -d "{
    \"client_id\": \"${DRIZZ_CLIENT_ID}\",
    \"client_secret\": \"${DRIZZ_CLIENT_SECRET}\",
    \"audience\": \"${DRIZZ_AUDIENCE}\",
    \"grant_type\": \"client_credentials\"
  }" | jq -r .access_token)

# 3 — upload the build. Skip this if the version is already registered
curl -s -X POST "${DRIZZ_BASE_URL}/apk/upload" \
  -H "x-api-key: ${DRIZZ_API_KEY}" \
  -F "file=@app-release.apk"

# 4 — trigger the test plan. Returns an execution_id
curl -s -X POST "${DRIZZ_BASE_URL}/testplan/run" \
  -H "x-api-key: ${DRIZZ_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "test_plan_id": "ADuF4ViN",
    "apks": { "com.shopease.android": "1.0.0" }
  }'
```

## Endpoints

| #  | Call            | Method and endpoint                            | Required                           | Returns                                      |
| -- | --------------- | ---------------------------------------------- | ---------------------------------- | -------------------------------------------- |
| 1  | Authenticate    | `POST https://<auth-domain>/oauth/token`       | Yes                                | `access_token`, valid 24 hours               |
| 2  | Upload a build  | `POST <DRIZZ_API_BASE_URL>/apk/upload`         | No — only when the version changes | Package name, version name, version code     |
| 3  | Trigger a run   | `POST <DRIZZ_API_BASE_URL>/testplan/run`       | Yes                                | `execution_id`                               |
| 3b | Trigger a batch | `POST <DRIZZ_API_BASE_URL>/testplan/run/batch` | No                                 | `successful_executions`, `failed_executions` |

If the version under test is already registered, skip call 2 and name the version in `apks` on call 3.

## Request headers

| Header         | Value                           | Applies to                                             |
| -------------- | ------------------------------- | ------------------------------------------------------ |
| `x-api-key`    | Access token from the auth call | Every call except `/oauth/token`                       |
| `Content-Type` | `application/json`              | `/oauth/token`, `/testplan/run`, `/testplan/run/batch` |
| `Content-Type` | `multipart/form-data`           | `/apk/upload`                                          |

The token header is `x-api-key`, not `Authorization: Bearer`. An `Authorization: Bearer` header is ignored and the call is rejected as unauthenticated. See [Authenticate](/automate-and-integrate/authenticate.md).

## Scope

| In scope                                                  | Not in scope                                               |
| --------------------------------------------------------- | ---------------------------------------------------------- |
| Authenticating an external system with client credentials | Polling a run's status                                     |
| Uploading a mobile app binary                             | Fetching results, reports or artifacts                     |
| Triggering one test plan                                  | JUnit, JSON or Allure export                               |
| Triggering several test plans in a batch                  | Webhooks or any callback on completion                     |
|                                                           | Creating or editing test plans, tests, modules or datasets |

A pipeline can start a run. It cannot wait for one or gate a build on the outcome. See [CI/CD](/automate-and-integrate/ci-cd.md).

## Rate limits

| Limit           | Value                                                                |
| --------------- | -------------------------------------------------------------------- |
| Sustained rate  | \~4 requests per second, per client                                  |
| Burst allowance | \~20 requests                                                        |
| Over the limit  | HTTP 429                                                             |
| Batch of plans  | Use `POST /testplan/run/batch` — one request instead of one per plan |

Back off with jitter after a 429. See [Errors & limits](/automate-and-integrate/errors-and-limits.md).

## Error codes

| Code    | Meaning           | What to do                                                            |
| ------- | ----------------- | --------------------------------------------------------------------- |
| **200** | Success           | Request accepted                                                      |
| **207** | Multi-Status      | Batch partially succeeded — inspect `failed_executions`               |
| **400** | Bad Request       | Validate the payload and parameters                                   |
| **404** | Not Found         | Verify the test plan ID and that the app version is registered        |
| **409** | Conflict          | This app version already exists — bump the version or skip the upload |
| **429** | Too Many Requests | Over the rate limit. Back off and retry                               |
| **500** | Server Error      | Contact `support@drizz.dev`                                           |
| **502** | Bad Gateway       | Retry, or check service availability                                  |

## Common mistakes

| What you did                                | What happens                                      |
| ------------------------------------------- | ------------------------------------------------- |
| Sent `Authorization: Bearer <token>`        | Rejected. The header is `x-api-key`               |
| Cached the token for a week                 | It expired after 24 hours. Requests start failing |
| Looped single triggers for 40 plans         | HTTP 429. Use the batch endpoint                  |
| Waited for the run to finish in your script | There is nothing to poll. The API ends at trigger |
| Uploaded the build on every pipeline run    | Re-uploading an existing version returns 409      |

## Next

* [Authenticate](/automate-and-integrate/authenticate.md) — get a token
* [Trigger a run](/automate-and-integrate/trigger-a-run.md) — start a test plan
* [Errors & limits](/automate-and-integrate/errors-and-limits.md) — status codes and retry behavior

***

*Last updated: 6 August 2026*
