Docs
CI API reference
The HTTP API the AppForShare CLI uses. Call it from any CI, script or tool to upload builds, find the newest one, move it between channels, read tester feedback and manage testers. Pro and Team; parts marked Team need a Team workspace.
Base URL: https://appforshare.io/api
Auth: Authorization: Bearer afs_... with an API token from Settings
Format: JSON in and out, except chunks (raw bytes) and file downloads. Errors answer with a message field.
Upload a build
Uploads are resumable: create the upload, send the file in chunks of up to 32 MB, then complete it. After a dropped connection, read the status to get the offset and go on from there. The X-Upload-Token from the first answer goes with every later call. This is the flow the CLI, GitHub Action, fastlane and Gradle plugins use.
POST/uploadsChanges data
Start an upload. fileName ends in .ipa, .apk or .aab; size is in bytes. Optional: releaseNotes (Pro and Team), channel (created on first use, Pro and Team), groups and testers to share the build with when it is ready (Team, up to 100 each). Answers id, token, chunkBytes and offset.
curl -s -X POST https://appforshare.io/api/uploads \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" \
-d '{"fileName":"app-release.apk","size":48211337,"releaseNotes":"Fixes the login crash","channel":"beta","groups":["Client QA"]}'
# {"id":"Q3vF8kL2mN0pR7sT","token":"...","chunkBytes":33554432,"offset":0}PUT/uploads/:id?offset=NChanges data
Send the next chunk as raw bytes, starting at offset. The answer is the new offset. A wrong offset answers 409 with the offset to use.
split -b 32m app-release.apk part_
offset=0
for p in part_*; do
curl -s -X PUT "https://appforshare.io/api/uploads/$ID?offset=$offset" \
-H "X-Upload-Token: $UPLOAD_TOKEN" -H "Content-Type: application/octet-stream" \
--data-binary @"$p"
offset=$((offset + $(wc -c < "$p")))
donePOST/uploads/:id/completeChanges data
Finish the upload. The build is queued for processing.
curl -s -X POST https://appforshare.io/api/uploads/$ID/complete -H "X-Upload-Token: $UPLOAD_TOKEN"GET/uploads/:id
Status: UPLOADING (with the offset received so far), QUEUED, PROCESSING, READY or FAILED (with error). When READY it has the install link url, the slug, expiresAt and, with a channel, the channel link.
curl -s https://appforshare.io/api/uploads/$ID -H "X-Upload-Token: $UPLOAD_TOKEN"
# {"id":"Q3vF8kL2mN0pR7sT","status":"READY","url":"https://appforshare.io/i/Stw0Ae","slug":"Stw0Ae","channel":{"name":"beta","url":"https://appforshare.io/c/..."},...}Account and builds
A build is addressed by its id or its link slug (:ref).
GET/ci/whoami
Email, workspace, role and plan of the token.
curl -s https://appforshare.io/api/ci/whoami -H "Authorization: Bearer $APPFORSHARE_TOKEN"GET/ci/projects
Projects with their ids and whether they are public or private to invited testers.
GET/ci/builds
Recent builds, newest first. Filters: platform (ios or android), app (bundle id or package name), project, channel, limit (1 to 100, default 20).
curl -s "https://appforshare.io/api/ci/builds?platform=android&app=com.example.shop&limit=5" -H "Authorization: Bearer $APPFORSHARE_TOKEN"GET/ci/builds/latest
The newest build that matches the same filters, or 404 when there is none. With channel: the build in that channel.
curl -s "https://appforshare.io/api/ci/builds/latest?channel=beta&platform=ios" -H "Authorization: Bearer $APPFORSHARE_TOKEN"GET/ci/builds/:ref
One build with its release notes, the store readiness report (status and each finding with a fix) and, on Pro and Team, the crash dashboard link for that version.
DELETE/ci/builds/:refChanges data
Delete a build. It can be restored from the dashboard for 7 days. Developer role.
Channels, links and release checklist
POST/ci/builds/:ref/channelChanges data
Put a build into a channel (created when missing); an older build is a rollback of the link. On Team a gated channel answers 409 with what is missing; force: true works for an Admin token. Pro and Team, Developer role.
curl -s -X POST https://appforshare.io/api/ci/builds/12345/channel \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"live"}'PATCH/ci/builds/:ref/linkChanges data
Link controls: paused (true or false), stopAt (an ISO date and time, or null), maxInstalls (a number, or null). Setting needs Pro or Team; removing works on any plan. Developer role.
curl -s -X PATCH https://appforshare.io/api/ci/builds/12345/link \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" \
-d '{"stopAt":"2026-12-31T23:59:59Z","maxInstalls":50}'PUT/ci/channels/testflightChanges data
Add the TestFlight public link to a channel (url), or remove it (url: null). Name the app with app (bundle id) or project. Pro and Team, Developer role.
curl -s -X PUT https://appforshare.io/api/ci/channels/testflight \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"beta","app":"com.example.shop","url":"https://testflight.apple.com/join/AbCd1234"}'GET/ci/builds/:ref/release
The release checklist of a build with its ticks, open release blockers and whether the gated channel takes it. Team.
PUT/ci/builds/:ref/release/checks/:keyChanges data
Tick or untick one step. Developer role. Team.
curl -s -X PUT https://appforshare.io/api/ci/builds/12345/release/checks/a1b2c3d4 \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" -d '{"done":true}'GET/ci/builds/:ref/test-plan/export?format=firebase|maestro
The AI test plan of the build as a YAML file: Firebase App Testing agent test cases (run with firebase apptesting:execute --test-dir; Android only, in preview) or a Maestro starter flow. The build needs a plan first. Pro and Team.
curl -s "https://appforshare.io/api/ci/builds/12345/test-plan/export?format=firebase" \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -o tests/app-testing.yamlFeedback and activity
GET/ci/feedback
Tester feedback, newest first: message, kind, device, build, whether it came from the in-app feedback link with its screen, how many screenshots, and a dashboard link. Filters: build (id or slug), status (open, resolved or all; default open).
curl -s "https://appforshare.io/api/ci/feedback?build=Stw0Ae&status=open" -H "Authorization: Bearer $APPFORSHARE_TOKEN"POST/ci/feedback/:id/trackerChanges data
Make a Linear or Jira issue from a report, with its screenshots, once a tracker is connected. Sent once per report. Pro and Team, Developer role.
curl -s -X POST https://appforshare.io/api/ci/feedback/678/tracker \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" -d '{"tracker":"jira"}'POST/ci/feedback/:id/taskChanges data
Add a task from a report to its project's task board, linked to the build. Team, Developer role.
GET/ci/activity
Workspace activity, newest first. Filters: project, kind (build, channel, feedback, task, release, link, tracker, tester), before (an activity id, for the next page), limit (1 to 100, default 50). Team.
curl -s "https://appforshare.io/api/ci/activity?kind=channel&limit=20" -H "Authorization: Bearer $APPFORSHARE_TOKEN"Testers and groups (Team)
Emails go in lists of up to 100 per call. An account can have up to 1,000 testers. Changes need the Developer role.
GET/ci/testers
Testers with their projects and groups. Filters: project, group (name).
curl -s "https://appforshare.io/api/ci/testers?group=Client%20QA" -H "Authorization: Bearer $APPFORSHARE_TOKEN"POST/ci/testersChanges data
Add testers: emails, optional project and groups (names). New testers get an invite unless notify is false.
curl -s -X POST https://appforshare.io/api/ci/testers \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" \
-d '{"emails":["[email protected]","[email protected]"],"project":42,"groups":["Client QA"]}'POST/ci/testers/importChanges data
Import a CSV as text: an email column, name or first and last name columns, a groups column (semicolon or pipe between several). Groups are made when missing. Up to 1,000 rows; invites only with notify: true, and then up to 200 new testers per import.
jq -Rs '{text: ., groups: ["Beta"]}' testers.csv | curl -s -X POST https://appforshare.io/api/ci/testers/import \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" --data @-POST/ci/testers/removeChanges data
With project: take away the access you gave by hand in that project (access through a group stays). Without: remove the testers from the workspace.
GET/ci/tester-groups
Groups with member counts and their projects.
POST/ci/tester-groupsChanges data
Make a group: name, optional project.
DELETE/ci/tester-groups/:nameChanges data
Delete a group. Its members stay testers.
POST/ci/tester-groups/:name/membersChanges data
Add members by email (made testers when new); notify defaults to true.
POST/ci/tester-groups/:name/members/removeChanges data
Take members out of a group.
POST/ci/builds/:ref/distributeChanges data
Share an uploaded build with groups and testers: the groups get its project, new addresses become testers, and they are emailed its install link (at most one email per tester per project in an hour). Up to 100 groups and testers together.
curl -s -X POST https://appforshare.io/api/ci/builds/12345/distribute \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" \
-d '{"groups":["Client QA"],"testers":["[email protected]"]}'Devices
POST/ci/devices/importChanges data
Import iPhone and iPad UDIDs as text: Firebase's Export Apple UDIDs file, Apple's Register Multiple Devices file or one UDID per line with an optional name. Up to 1,000 per call. Answers added, known, named and the skipped lines with a reason. Developer role.
jq -Rs '{text: .}' firebase-udids.txt | curl -s -X POST https://appforshare.io/api/ci/devices/import \
-H "Authorization: Bearer $APPFORSHARE_TOKEN" -H "Content-Type: application/json" --data @-GET/ci/devices/apple-devices.txt
Your devices in Apple's Register Multiple Devices format, for the Apple portal or fastlane register_devices.
curl -s https://appforshare.io/api/ci/devices/apple-devices.txt -H "Authorization: Bearer $APPFORSHARE_TOKEN" -o devices.txtQuestions
- Which plan do I need?
- API tokens come with Pro and Team. Testers, groups, distribute, the release checklist, tasks and activity need Team. Make a token under Dashboard, Settings, API tokens.
- What can a token do?
- The same as its creator in that workspace, with their role: a Viewer token only reads. Revoke a token in Settings and it stops at once.
- Is there a rate limit?
- Yes. Adding testers, adding group members and distribute share 20 calls an hour per workspace, tester imports 10 an hour and device imports 30 an hour. An answer of 429 means wait and try again.
- Do I have to use the API?
- No. The CLI does all of this with one command per job, and the GitHub Action, fastlane plugin and MCP server use the same calls.
Prefer commands? See the CLI, GitHub Action, fastlane and Gradle guide, or connect an AI tool through the MCP server.