Every account gets a free REST API. One POST to /upload.php uploads an .ipa, .apk, or .aab and returns the shareable install link. Works with GitHub Actions, GitLab CI, Bitrise, Fastlane, or a raw curl in a shell script.
Sign up free or log in to get your API token.
POST https://apponthego.com/upload.php
Single endpoint. Uploads use multipart/form-data. Same endpoint the browser uses — CI just sends a Bearer token instead of a session cookie.
Pass your token in one of three ways (Bearer header preferred):
Authorization: Bearer 0b6079183e35159c4a64169a942e6493fa47ab
curl -F file=@build.ipa "https://apponthego.com/upload.php?token=YOUR_TOKEN"
Get your token from this page (logged in), or regenerate any time. Regenerating invalidates the previous token instantly.
| Field | Type | Required | Description |
|---|---|---|---|
file | file | yes | .ipa, .apk, or .aab. AABs are auto-converted server-side via bundletool. |
is_public | 0|1 | no | 1 to feature on the public Wall of Apps. Default 1. |
password | string | no | Set an install-page password. Free-tier feature. |
stable_slug | string | no | Rebind the given slug to this build. Slug format: [a-z0-9][a-z0-9\-]{1,30}[a-z0-9]. |
expires_in_seconds | int | no | Auto-expiry. 0 = "Never" (paid tiers only). Capped by your plan's link_lifetime_days. |
200 OK — body is the plaintext install URL:
https://i.apponthego.com/myapp-beta
Errors — 4xx / 5xx with a plaintext reason. Common codes: 400 (bad params), 409 (slug taken by another user), 413 (too large for your plan), 500 (server error).
The full example — bearer auth, stable slug, 7-day expiry, Slack-friendly output:
curl -X POST https://apponthego.com/upload.php \
-H "Authorization: Bearer $AOTG_TOKEN" \
-F "file=@./build/MyApp.ipa" \
-F "stable_slug=myapp-beta" \
-F "expires_in_seconds=604800" \
-F "is_public=1"
Drop this into your Fastfile after gym / build_app:
lane :ship_beta do
build_app(scheme: "MyApp")
ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
response = sh(
"curl -sf -H 'Authorization: Bearer #{ENV['AOTG_TOKEN']}' " \
"-F 'file=@#{ipa_path}' " \
"-F 'stable_slug=myapp-beta' " \
"-F 'expires_in_seconds=604800' " \
"https://apponthego.com/upload.php"
).strip
slack(message: "New iOS build ready: #{response}") if response.start_with?("http")
end
Add a step to your build workflow (secrets: AOTG_TOKEN):
- name: Push to App On The Go
run: |
URL=$(curl -sf -X POST \
-H "Authorization: Bearer ${{ secrets.AOTG_TOKEN }}" \
-F "file=@build/MyApp.ipa" \
-F "stable_slug=myapp-beta" \
-F "expires_in_seconds=1209600" \
https://apponthego.com/upload.php)
echo "INSTALL_URL=$URL" >> $GITHUB_ENV
echo "::notice::Installable at $URL"
- script:
title: Push to App On The Go
inputs:
- content: |
#!/usr/bin/env bash
set -e
URL=$(curl -sf -X POST \
-H "Authorization: Bearer $AOTG_TOKEN" \
-F "file=@$BITRISE_IPA_PATH" \
-F "stable_slug=$BITRISE_APP_TITLE-beta" \
https://apponthego.com/upload.php)
envman add --key AOTG_INSTALL_URL --value "$URL"
Save a Slack / Discord / Teams / generic webhook URL in Settings and every upload (including from the API) automatically posts to your channel. No extra API call needed.
Currently no hard rate limit — but keep uploads reasonable (5+ min between builds of the same app is a normal CI pattern). Persistent abuse of the free tier may get throttled.
Get a token, add one curl to your CI, testers get every build automatically.