---
title: Upload Application
slug: devicepark/sdk-documentation/applications/upload-application
description: Upload APK or IPA files with optional image injection.
docTags: 
createdAt: 2026-08-10T08:03:45.197Z
---

Use this method to upload an APK or IPA artifact that will be used by your test system.

The SDK sends the file as a binary stream. Do not convert the file to Base64 or wrap it in JSON.

## Before You Begin

- Confirm that the APK or IPA is readable by the test runner.
- Choose a meaningful version label for the build.
- Keep the source stream open until the upload method completes.
- Enable image injection only when the test workflow requires Device Park gadget injection.

## SDK Method

| Java                                                                      | Node.js                                                                          | .NET                                                                                |
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `client.applications().upload(stream, fileName, version, imageInjection)` | `await client.applications().upload(stream, fileName, version, imageInjection?)` | `await client.Applications.UploadAsync(stream, fileName, version, imageInjection?)` |

Every SDK keeps the three-parameter call for normal uploads. `imageInjection` defaults to `false`.

## Parameters

| Parameter        | Type            | Required | Validation                        | Description                         |
| ---------------- | --------------- | -------- | --------------------------------- | ----------------------------------- |
| `stream`         | readable stream | Yes      | Must contain readable binary data | APK or IPA content                  |
| `fileName`       | string          | Yes      | Must not be blank                 | Original file name                  |
| `version`        | string          | Yes      | Non-blank, maximum 50 characters  | Build version label                 |
| `imageInjection` | boolean         | No       | Default `false`                   | Enables configured gadget injection |

## Request Mapping and Headers

The upload is a binary stream, not JSON and not Base64.

| SDK input        | Transport mapping                             |
| ---------------- | --------------------------------------------- |
| `stream`         | Request body with `application/octet-stream`  |
| `fileName`       | `file-name` header                            |
| `version`        | `version` header                              |
| `imageInjection` | `image-injection` header as `true` or `false` |

OAuth authorization and other transport headers are added by the SDK client.

## Standard Upload

:::CodeblockTabs
```java
try (InputStream input = Files.newInputStream(Paths.get("/path/to/mobile-app.apk"))) {
    Application application = client.applications().upload(
            input,
            "mobile-app.apk",
            "1.0.0"
    );

    System.out.println(application.fileKey());
}
```

```typescript
import { createReadStream } from "node:fs";

const application = await client.applications().upload(
  createReadStream("/path/to/mobile-app.apk"),
  "mobile-app.apk",
  "1.0.0"
);

console.log(application.fileKey);
```

```csharp
using var apk = File.OpenRead("/path/to/mobile-app.apk");

var application = await client.Applications.UploadAsync(
    apk,
    "mobile-app.apk",
    "1.0.0");

Console.WriteLine(application.FileKey);
```
:::

## Upload with Image Injection

Use image injection only when the test scenario depends on Device Park gadget injection.

:::CodeblockTabs
```java
try (InputStream input = Files.newInputStream(Paths.get("/path/to/mobile-app.apk"))) {
    Application application = client.applications().upload(
            input,
            "mobile-app.apk",
            "1.0.0",
            true
    );
}
```

```typescript
import { createReadStream } from "node:fs";

const application = await client.applications().upload(
  createReadStream("/path/to/mobile-app.apk"),
  "mobile-app.apk",
  "1.0.0",
  true
);
```

```csharp
using var apk = File.OpenRead("/path/to/mobile-app.apk");

var application = await client.Applications.UploadAsync(
    apk,
    "mobile-app.apk",
    "1.0.0",
    imageInjection: true);
```
:::

:::hint{type="info"}
Omit `imageInjection` or pass `false` for a standard upload. Passing `true` changes upload processing and should be enabled only for workflows that require it.
:::

## Result

The method returns one `Application`.

| Field              | Type            | Nullable | Meaning                                                                                                 |
| ------------------ | --------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `revision`         | number          | Yes      | Stored artifact revision                                                                                |
| `sizeInBytes`      | number          | Yes      | Uploaded artifact size                                                                                  |
| `version`          | string          | Yes      | Version supplied to `upload(...)`                                                                       |
| `fileKey`          | string          | Yes      | Stable application identifier                                                                           |
| `filePath`         | string          | Yes      | Server-side storage path                                                                                |
| `downloadUrl`      | string          | Yes      | Potentially time-limited download URL                                                                   |
| `createdAt`        | ISO-8601 string | Yes      | Creation timestamp                                                                                      |
| `bundleId`         | string          | Yes      | IPA bundle identifier, for example `com.example.app`. IPA only                                          |
| `title`            | string          | Yes      | Application name read from the IPA `Info.plist`. IPA only                                               |
| `ipaVersion`       | string          | Yes      | Version read from the IPA `Info.plist`. Can differ from the `version` passed to `upload(...)`. IPA only |
| `enterprise`       | boolean         | Yes      | `true` when the IPA is signed with an enterprise provisioning profile. IPA only                         |
| `minimumOsVersion` | string          | Yes      | Lowest iOS version the IPA supports, for example `13.0`. IPA only                                       |
| `minSdkVersion`    | number          | Yes      | Lowest Android API level the APK supports, for example `24`. APK only                                   |

### Artifact Metadata

Device Park inspects the uploaded artifact and returns what it can read from it. IPA uploads carry `bundleId`, `title`, `ipaVersion`, `enterprise` and `minimumOsVersion`, APK uploads carry `minSdkVersion`. Metadata that cannot be read is `null`; the artifact is still stored, because metadata extraction never fails an upload.

The stored metadata is also returned by [List Applications](docId\:SPDXnMADbDctpaPsO1gbH), so it does not have to be cached after upload.

APK response:

```json
{
  "revision": 1,
  "sizeInBytes": 24576000,
  "version": "1.0.0",
  "fileKey": "mobile-app.apk",
  "filePath": "applications/mobile-app.apk",
  "downloadUrl": "https://devicepark.testinium.io/temporary-download-url",
  "createdAt": "2026-07-28T09:00:00Z",
  "minSdkVersion": 24
}
```

IPA response:

```json
{
  "revision": 1,
  "sizeInBytes": 31457280,
  "version": "1.0.0",
  "fileKey": "mobile-app.ipa",
  "filePath": "applications/mobile-app.ipa",
  "downloadUrl": "https://devicepark.testinium.io/temporary-download-url",
  "createdAt": "2026-07-28T09:00:00Z",
  "bundleId": "com.example.app",
  "title": "Example App",
  "ipaVersion": "3.2.1",
  "enterprise": true,
  "minimumOsVersion": "13.0"
}
```

Store `fileKey`; it is the stable application identifier. `downloadUrl` may expire and should not replace `fileKey` in your data model.

The caller owns the input stream lifecycle. Java should use try-with-resources.

Uploading stores the application artifact. Device installation and test-session behavior are separate steps controlled by the consuming test flow.

Image injection changes upload processing only. Passing `false` or omitting the parameter preserves the standard upload behavior.

## Next Step

[List applications](docId\:SPDXnMADbDctpaPsO1gbH) to inspect the stored revision or keep the returned `fileKey` in the test configuration.
