Permission Required: project:manage-build-storage
Initiate a build upload. The API automatically selects single-part or multipart upload based on file size.
For most users, we recommend using the CLI or GitHub Action instead of the API directly.
Upload Methods
| Method | File Size | Use Case |
|---|
| Single-part | < 3GB | Simple uploads |
| Multipart | ≥ 3GB (up to 5TB) | Large files, parallel uploads |
The API automatically uses multipart for files ≥3GB unless you explicitly set multipart: false.
Request Body
Build name (1-255 characters)
File name (1-255 characters)
Size in bytes (positive integer)
Target platform: windows, macos, linux, android, ios-native, ios-simulator, xbox, playstation
Description (max 1000 characters)
Force multipart upload. Auto-enabled for files ≥3GB.
Auto-delete old builds when storage capacity is reached
deletion_policy
string
default:"least_recent"
Deletion policy: least_recent (LRU) or oldest (FIFO)
Timeout in minutes (1-1440). Default: 10 for single-part, 60 for multipart.
Array of tags (1-50 characters each)
Build metadata (VCS, CI, app info)
Version control metadata
VCS type: git, mercurial, svn
Provider: github, gitlab, bitbucket, azure-devops
Commit info (hash, short_hash, message, author, timestamp)
CI/CD metadata (system, build_number, job_name, run_url)
App metadata (version, version_code, build_number, bundle_id)
Response (Single-Part)
Build ID for completing the upload
Presigned URL to PUT the file
Object key for the upload
Response (Multipart)
Build ID for completing the upload
Upload ID for getting part URLs
Object key for the upload
Total number of parts to upload
Size of each part in bytes (typically 100MB)
curl -X POST "https://nunu.ai/api/v1/builds/upload" \
-H "X-Api-Key: YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"project_id": "your-project-id",
"name": "Production Build v1.2.3",
"file_name": "app-release.apk",
"file_size": 52428800,
"platform": "android",
"multipart": false,
"auto_delete": true,
"tags": ["version:1.2.3", "env:production"],
"details": {
"vcs": {
"commit": { "short_hash": "a1b2c3d" },
"branch": "main"
}
}
}'
{
"upload_type": "single-part",
"build_id": "123e4567-e89b-12d3-a456-426614174000",
"upload_url": "https://storage.example.com/...",
"object_key": "abc123-def456/app-release.apk"
}
Upload Flow
Single-Part Upload
Multipart Upload
Initiate
POST to /builds/upload with multipart: false
Upload
PUT the file to the returned upload_url
Complete
POST to /builds/upload/complete
Initiate
POST to /builds/upload (automatic for files ≥3GB)
Get Part URLs
GET /builds/upload/parts for presigned URLs
Upload Parts
PUT each part to its URL, save ETags
Complete
POST to /builds/upload/complete with ETags
Complete Single-Part Example
#!/bin/bash
PROJECT_ID="your-project-id"
API_TOKEN="your-api-token"
FILE_PATH="build/app.apk"
# Step 1: Initiate
RESPONSE=$(curl -s -X POST \
"https://nunu.ai/api/v1/builds/upload" \
-H "Content-Type: application/json" \
-H "X-Api-Key: $API_TOKEN" \
-d "{
\"project_id\": \"$PROJECT_ID\",
\"name\": \"Production Build\",
\"file_name\": \"$(basename $FILE_PATH)\",
\"file_size\": $(stat -f%z $FILE_PATH 2>/dev/null || stat -c%s $FILE_PATH),
\"platform\": \"android\",
\"multipart\": false
}")
UPLOAD_URL=$(echo $RESPONSE | jq -r '.upload_url')
BUILD_ID=$(echo $RESPONSE | jq -r '.build_id')
# Step 2: Upload
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/octet-stream" \
--data-binary "@$FILE_PATH"
# Step 3: Complete
curl -X POST \
"https://nunu.ai/api/v1/builds/upload/complete" \
-H "Content-Type: application/json" \
-H "X-Api-Key: $API_TOKEN" \
-d "{\"build_id\": \"$BUILD_ID\"}"
echo "Upload complete! Build ID: $BUILD_ID"
API key for authentication
Size in bytes (positive integer)
Available options:
windows,
macos,
linux,
android,
ios-native,
ios-simulator,
xbox,
playstation
Description (max 1000 chars)
Use multipart upload? (Auto for files ≥3GB)
Auto-delete old builds when capacity reached
deletion_policy
enum<string>
default:least_recent
Available options:
least_recent,
oldest
Timeout in minutes (1-1440)
Array of tags (1-50 chars each)
Upload initiated successfully
Allowed value: "single-part"