Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 74 additions & 28 deletions src/pages/docs/api/binary-apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,33 @@ curl -X GET "https://api.test.io/customer/v2/binary_apps/upload_url" \

**Response:** `200 OK`

**Response Attributes:**

- `binary_app_id` (number, required) - The ID of the created binary app (use this in the finalization step)
- `url` (string, required) - S3 presigned POST URL
- `fields` (object, required) - Form fields required for the S3 POST request
- `key` (string, required) - S3 object key pattern. **IMPORTANT:** `${filename}` is a placeholder - replace it with your actual filename when uploading to S3. For example, if uploading `MyApp-v1.2.3.apk`, the key should be `uploads/binary_app/package/123/MyApp-v1.2.3.apk`
- `success_action_status` (string, required) - HTTP status code S3 will return on success
- `policy` (string, required) - Base64-encoded upload policy
- `x-amz-credential` (string, required) - AWS credential for the upload
- `x-amz-algorithm` (string, required) - AWS signature algorithm
- `x-amz-date` (string, required) - Request timestamp
- `x-amz-signature` (string, required) - Request signature

{% code language="json" showLineNumbers=true %}

```json
{
"binary_app_id": 123,
"url": "https://upload.test.io/direct",
"url": "https://my-bucket.s3.eu-west-1.amazonaws.com",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the url that a user will get?

@danielvysotskyi danielvysotskyi Nov 12, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that is upload url for S3, that is direct upload to S3 that bypass our infrastructure so here will be AWS link not ours
also that is a reason why we should do 3-rd step with metadata for carierwave that connects each step and provide public url for download

@danielvysotskyi danielvysotskyi Nov 12, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our part here are signature attribute and policy where we provide limitation for upload.
all those fields that we returns with presigned url like a signature for document, that like tell AWS "yes you can allow upload this time, here you have my signature as proof"

"fields": {
"key": "uploads/binary_app/123/${filename}",
"key": "uploads/binary_app/package/123/${filename}",
"success_action_status": "201",
"policy": "<opaque-policy>",
"algorithm": "<signature-algorithm>",
"date": "20251104T154715Z",
"signature": "<signature>"
"policy": "eyJleHBpcmF0aW9uIjoiMjAyNS0xMS0wNFQxNjo0NzoxNVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJteS1idWNrZXQifSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVwbG9hZHMvYmluYXJ5X2FwcC9wYWNrYWdlLzEyMy8iXSx7InN1Y2Nlc3NfYWN0aW9uX3N0YXR1cyI6IjIwMSJ9LFsiY29udGVudC1sZW5ndGgtcmFuZ2UiLDEsMTA3Mzc0MTgyNF1dfQ==",
"x-amz-credential": "AKIAEXAMPLE/20251104/eu-west-1/s3/aws4_request",
"x-amz-algorithm": "AWS4-HMAC-SHA256",
"x-amz-date": "20251104T154715Z",
"x-amz-signature": "abc123def456..."
}
}
```
Expand All @@ -86,30 +100,25 @@ curl -X GET "https://api.test.io/customer/v2/binary_apps/upload_url" \

## Finalize binary app upload

Finalize a direct upload by validating metadata, verifying the file exists in storage, and generating a public download URL.
Finalizes a direct storage upload by validating metadata, verifying the file exists in storage, and generating a public download URL.

**Important:** After uploading to S3, you have to call this endpoint with the file metadata to complete the process.

**Endpoint:** `PUT /binary_apps/{id}`

**Parameters:**

- `id` (number, required) - Binary app ID from GET /binary_apps/upload_url
- `id` (number, required) - Binary app ID from `GET /binary_apps/upload_url`

**Request Body:**

{% code language="json" showLineNumbers=true %}
**Request Body Attributes:**

```json
{
"filename": "MyApp-v1.2.3.apk",
"file_size": 524288000,
"content_type": "application/vnd.android.package-archive",
"bundle_identifier": "com.example.myapp",
"bundle_version": "1.2.3",
"url": "https://files.test.io/uploads/binary_app/13/MyApp-v1.2.3.apk"
}
```

{% /code %}
- `filename` (string, required) - The name of the file uploaded to S3. Must match the filename used in the S3 upload. Used to construct the S3 key for verification.
- `file_size` (number, required) - Size of the uploaded file in bytes. Must not exceed 1GB (1073741824 bytes). This should match the actual file size uploaded to S3.
- `content_type` (string, required) - MIME type of the uploaded file. Common values:
- `application/vnd.android.package-archive` - APK (Android)
- `application/octet-stream` - IPA (iOS)
- `bundle_identifier` (string, optional) - The unique bundle/package identifier for the app (e.g., `com.example.myapp` for Android or iOS).
- `bundle_version` (string, optional) - The version string of the app bundle (e.g., `1.2.3` or `4.2.11.5100000`).

**Example Request:**

Expand All @@ -124,15 +133,25 @@ curl -X PUT "https://api.test.io/customer/v2/binary_apps/123" \
"file_size": 524288000,
"content_type": "application/vnd.android.package-archive",
"bundle_identifier": "com.example.myapp",
"bundle_version": "1.2.3",
"url": "https://testcloud-staging-webapp.s3.eu-west-1.amazonaws.com/uploads/binary_app/package/13/MyApp-v1.2.3.apk"
"bundle_version": "1.2.3"
}'
```

{% /code %}

**Response:** `200 OK`

**Response Attributes:**

- `binary_app` (object)
- `id` (number) - Binary app ID
- `filename` (string) - The uploaded file name
- `file_size` (number) - File size in bytes
- `content_type` (string) - File MIME type
- `bundle_identifier` (string, nullable) - App bundle identifier
- `bundle_version` (string, nullable) - App version
- `status` (string) - Binary app status

{% code language="json" showLineNumbers=true %}

```json
Expand All @@ -141,22 +160,49 @@ curl -X PUT "https://api.test.io/customer/v2/binary_apps/123" \
"id": 123,
"filename": "MyApp-v1.2.3.apk",
"file_size": 524288000,
"url": "https://files.test.io/uploads/binary_app/123/MyApp-v1.2.3.apk"
"content_type": "application/vnd.android.package-archive",
"bundle_identifier": "com.example.myapp",
"bundle_version": "1.2.3",
"status": "new"
}
}
```

{% /code %}

**Error Response:** `400 Bad Request`

Returned when required parameters are missing:

{% code language="json" showLineNumbers=true %}

```json
{
"error": "filename is missing, file_size is missing, content_type is missing"
}
```

{% /code %}

**Error Response:** `422 Unprocessable Entity`

If the file is not found in storage, returns:
Returned when the file doesn't exist in S3 or validation fails:

{% code language="json" showLineNumbers=true %}

```json
{
"error": "File not found in S3: uploads/binary_app/package/123/MyApp-v1.2.3.apk"
}
```

{% /code %}

{% code language="json" showLineNumbers=true %}

```json
{
"error": "File not found: uploads/binary_app/123/MyApp-v1.2.3.apk"
"error": "Validation failed: File size exceeds the maximum allowed size of 1GB"
}
```

Expand Down