> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mobilerun.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Install app

> Requests an app install on the device. The request body must supply exactly one of an Android packageName or an iOS bundleId; optional country and versionCode select an exact regional uploaded Android version, and protected packages are rejected. background (default false) selects the response contract: false installs inline and returns the outcome directly (200 on success, an error status on failure); true accepts the request and runs the download + install in the background, returning 202 immediately — poll list-app-installs for the backend's view of that attempt's status. Refuses with 409 once 2 other installs are already running on the device, in either mode; a repeat request for an app that already has an install running is also refused with 409 rather than superseding it — retry once that attempt reaches a terminal state.

Requests an app install on the device. `background` (default `false`) selects the response contract:

* `background: false` (default) — installs inline; the response is the actual outcome: `200` on success, an error status on failure.
* `background: true` — accepts the request and runs the download + install in the background; a `202` response means the request was accepted, not that the app is installed yet — poll `list-apps` until the app appears, or poll `list-app-installs` for the backend's view of the install attempt itself (useful while the device is offline or crashed, when `list-apps` can't be called at all).

Both modes are subject to the same concurrency cap: a request is refused with `409 Conflict` once 2 other installs are already running on the device. A repeat request for an app that already has an install running is also refused with `409 Conflict` rather than superseding it — retry once that attempt reaches a terminal state.

Provide **exactly one** of:

* `packageName` — Android package name. Resolved against the device owner's app library, so upload the APK first.
* `bundleId` — iOS bundle identifier (e.g. `com.example.app`) or a numeric App Store ID. The app is installed from the App Store.

Uploaded Android app versions may additionally be selected with:

* `country` — ISO 3166-1 alpha-2 country stored on the uploaded version (for example, `MY` or `SG`).
* `versionCode` — exact uploaded app version code.

Pass both fields when the app library contains multiple regional versions for the same package name. Omitting them preserves the legacy lookup behavior, including Apps API's default `US` country.

<Warning>
  Protected system packages cannot be installed over. Requests targeting a protected package fail with `403 Forbidden`.
</Warning>


## OpenAPI

````yaml /api-reference/phones/tools.yaml post /devices/{deviceId}/apps
openapi: 3.1.0
info:
  title: Tools
  version: v1
servers:
  - description: Droidrun Cloud API
    url: https://api.mobilerun.ai/v1
security:
  - bearerAuth: []
paths:
  /devices/{deviceId}/apps:
    post:
      tags:
        - Apps
      summary: Install app
      description: >-
        Requests an app install on the device. The request body must supply
        exactly one of an Android packageName or an iOS bundleId; optional
        country and versionCode select an exact regional uploaded Android
        version, and protected packages are rejected. background (default false)
        selects the response contract: false installs inline and returns the
        outcome directly (200 on success, an error status on failure); true
        accepts the request and runs the download + install in the background,
        returning 202 immediately — poll list-app-installs for the backend's
        view of that attempt's status. Refuses with 409 once 2 other installs
        are already running on the device, in either mode; a repeat request for
        an app that already has an install running is also refused with 409
        rather than superseding it — retry once that attempt reaches a terminal
        state.
      operationId: install-app
      parameters:
        - in: path
          name: deviceId
          required: true
          schema:
            type: string
        - in: header
          name: X-Device-Display-ID
          schema:
            default: 0
            format: int64
            minimum: 0
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - additionalProperties: false
                  properties:
                    background:
                      default: false
                      description: >-
                        true: return 202 immediately and install in the
                        background (poll list-app-installs). false/omitted:
                        install inline and return the outcome directly (200 on
                        success, an error status on failure).
                      type: boolean
                    bundleId:
                      description: iOS bundle identifier (e.g. com.example.app)
                      minLength: 1
                      type: string
                  required:
                    - bundleId
                  type: object
                - additionalProperties: false
                  properties:
                    background:
                      default: false
                      description: >-
                        true: return 202 immediately and install in the
                        background (poll list-app-installs). false/omitted:
                        install inline and return the outcome directly (200 on
                        success, an error status on failure).
                      type: boolean
                    country:
                      description: >-
                        Optional ISO 3166-1 alpha-2 country of the uploaded app
                        version (e.g. MY or SG).
                      pattern: ^[A-Za-z]{2}$
                      type: string
                    packageName:
                      description: Android package name (e.g. com.example.app)
                      minLength: 1
                      type: string
                    versionCode:
                      description: >-
                        Optional exact app-library version code. Use with
                        country when multiple regional versions share an
                        identifier.
                      minimum: 1
                      type: integer
                  required:
                    - packageName
                  type: object
              properties:
                background:
                  default: false
                  description: >-
                    true: return 202 immediately and install in the background
                    (poll list-app-installs). false/omitted: install inline and
                    return the outcome directly (200 on success, an error status
                    on failure).
                  type: boolean
                bundleId:
                  description: iOS bundle identifier (e.g. com.example.app)
                  minLength: 1
                  type: string
                country:
                  description: >-
                    Optional ISO 3166-1 alpha-2 country of the uploaded app
                    version (e.g. MY or SG).
                  pattern: ^[A-Za-z]{2}$
                  type: string
                packageName:
                  description: Android package name (e.g. com.example.app)
                  minLength: 1
                  type: string
                versionCode:
                  description: >-
                    Optional exact app-library version code. Use with country
                    when multiple regional versions share an identifier.
                  minimum: 1
                  type: integer
              type: object
        required: true
      responses:
        '200':
          description: Install finished synchronously (background omitted or false).
        '202':
          description: Accepted
      security:
        - bearerAuth: []
      x-codeSamples:
        - lang: JavaScript
          source: |-
            import Mobilerun from '@mobilerun/sdk';

            const client = new Mobilerun({
              apiKey: process.env['MOBILERUN_CLOUD_API_KEY'], // This is the default and can be omitted
            });

            await client.devices.apps.install('deviceId', { bundleId: 'x' });
        - lang: Python
          source: |-
            import os
            from mobilerun_sdk import Mobilerun

            client = Mobilerun(
                api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"),  # This is the default and can be omitted
            )
            client.devices.apps.install(
                device_id="deviceId",
                bundle_id="x",
            )
components:
  securitySchemes:
    bearerAuth:
      bearerFormat: Opaque
      description: Bearer token via Authorization header
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.