getting started

using forgeQueue

Push to a branch, get a signed iOS or Android build back — no Mac required, no CI file to write. This page is public — link it to anyone connecting a repo, logged in or not.

1.0 — six stages, one push

Steps 1–3 are one-time setup per repo; from then on, step 4 is the whole workflow.

  1. 1.0

    Sign in and link your repo

    Sign in with GitHub, install the forgeQueue GitHub App on the repository (or the whole org). Add the repo from the dashboard — forgeQueue creates a dedicated CI branch for it, forgeQueue/ci-release by default.

  2. 2.0

    Tell it what to build

    Turn on iOS, Android, or both — they build independently from the same push. If the project lives in a subfolder, as in a monorepo with separate /ios and /android trees, set that path too. Optionally point each platform at its own branch instead of sharing the repo's default CI branch, so a push to one triggers only that platform.

  3. 3.0

    Set up code signing

    iOS needs a distribution certificate and provisioning profile — upload your own .p12/.mobileprovision, or save a Team API key from App Store Connect and let forgeQueue generate them for you. Android takes a keystore, its password, and a key alias + password. Save signing once as your team default, or override it per repo.

  4. 4.0

    Push

    No pipeline file, no YAML — a push to the CI branch is the whole trigger:
    git push origin forgeQueue/ci-release

  5. 5.0

    Watch it run

    The dashboard streams the build log live, shows queue position and ETA, credits charged, and — on failure — an automatic diagnosis of what went wrong.

  6. 6.0

    Get your build

    A successful build is pushed straight back into your own repo — never onto the CI branch, so grabbing it never triggers another one. It lands on its own branch instead: forgeQueue/builds, at forgequeue-builds/<build-id>/app.ipa (or .aab). Each build keeps its own folder — nothing is ever overwritten.

7.0 — TestFlight & Play Console uploads

Optional, per repo. Turn on "TestFlight upload" (iOS) or "Play Console upload" (Android) on a repo's page and every successful build after that is pushed straight to TestFlight or the Play Console internal testing track — no extra step, the push that starts the build is still the only trigger. iOS reuses whichever App Store Connect API key already signs the repo (and checks live that it actually has App Manager access before turning on, not just Developer). Android needs a one-time Google Play service account key uploaded on your team's Android signing page.

8.0 — billing

Builds are charged by build time, whether they succeed or fail — the compute ran either way, the same logic every CI provider bills by. The estimate shown before a build is your own historical average once you have one, a flat default before that. A low balance holds a build rather than failing the push outright; it runs automatically once topped up.

9.0 — API access

For checking build status, managing env vars/config files, platform config, and the TestFlight/Play Console toggles from your own scripts or CI — generate a key on Account → Team.

Every request needs an Authorization header with your team's key:

curl https://forgequeue.8rec.com/api/public/builds \
  -H "Authorization: Bearer fq_live_..."

Lists your team's builds, newest first — id, repoId, platform, status, commit, branch, credits, and artifact path, but not the log (see below for that). Filter with ?repoId=, ?platform=, ?status=; page with ?limit= (default 20, max 100) and ?cursor= (from the previous response's nextCursor).

curl https://forgequeue.8rec.com/api/public/builds/<build-id> \
  -H "Authorization: Bearer fq_live_..."

Same fields as the list, plus the full build log.

Env vars and config files

Read/write — same Env page a repo's build reads from. PUT replaces the plain env vars; PUT/DELETE on the files route manages one gitignored config file (GoogleService-Info.plist, google-services.json, ...) at a time by its target path in the repo.

curl -X PUT https://forgequeue.8rec.com/api/public/repos/<repo-id>/env \
  -H "Authorization: Bearer fq_live_..." \
  -H "Content-Type: application/json" \
  -d '{"dotenv": "NEXT_PUBLIC_API_URL=https://api.example.com"}'

curl -X PUT https://forgequeue.8rec.com/api/public/repos/<repo-id>/env/files \
  -H "Authorization: Bearer fq_live_..." \
  -F "targetPath=ios/App/App/GoogleService-Info.plist" \
  -F "file=@./GoogleService-Info.plist"

Platform config

Same fields as the dashboard's Platforms panel — platform is ios or android, path is the subfolder relative to the repo root (omit or use "" for repo root), branch overrides the repo's default CI branch for just this platform. Omitting path or branch leaves it exactly as it already is — it's a partial update, not a reset.

curl -X PATCH https://forgequeue.8rec.com/api/public/repos/<repo-id>/platforms \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"platform": "ios", "enabled": true, "path": "ios-native/App"}'

iOS App ID capabilities

Associated Domains, Push Notifications, Sign in with Apple, and the rest of the supported list each need enabling on the App ID itself, then the provisioning profile regenerated to actually carry it — an already-issued profile doesn't pick up a capability turned on afterward. PATCH does both in one call: flips it on App Store Connect, then re-issues the profile bound to the same certificate. Only works for a forgeQueue-generated certificate — nothing to regenerate against for one you uploaded yourself.

curl https://forgequeue.8rec.com/api/public/repos/<repo-id>/signing/capabilities \
  -H "Authorization: Bearer fq_live_..."

curl -X PATCH https://forgequeue.8rec.com/api/public/repos/<repo-id>/signing/capabilities \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"capability": "ASSOCIATED_DOMAINS", "enabled": true}'

TestFlight & Play Console toggles

Same toggles as the repo page. Turning TestFlight on runs the same App Manager check the dashboard does and rejects with a clear error if the key on file can't actually submit builds. TestFlight also needs the app already registered on App Store Connect under its bundle ID — that part isn't scriptable (Apple's API has no "create app" endpoint, still App Store Connect-website-only), but whether it's registered yet is checkable instead of guessed:

curl -X PATCH https://forgequeue.8rec.com/api/public/repos/<repo-id>/testflight \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"enabled": true}'

curl https://forgequeue.8rec.com/api/public/repos/<repo-id>/signing/app-status \
  -H "Authorization: Bearer fq_live_..."
# -> { "bundleId": "...", "registered": true, "appleId": "..." }

# already know the numeric id, or want to skip waiting on auto-detect?
curl -X PATCH https://forgequeue.8rec.com/api/public/repos/<repo-id>/signing/app-status \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"appleId": "1234567890"}'   # or {"appleId": null} to clear it

Managing testers

TestFlight: forgeQueue keeps one external beta group per app, "forgeQueue testers" (created automatically the first time you call this), with access to every future build turned on — no per-build assignment needed. Apple's own auto-managed "Internal Testing" group is separate and can't be touched by email via the API at all. Play Console: internal-track testers aren't scoped to one repo — the team's one service account key covers every Android app — so pass packageName explicitly (body field or query param, either works); PATCH replaces the list in full, it doesn't add to it. Google's own API only supports adding a Google Group to the internal track, not a bare individual email — manage tester emails as membership of a Google Group in Google Admin, then point this endpoint at that group.

curl https://forgequeue.8rec.com/api/public/repos/<repo-id>/testflight/testers \
  -H "Authorization: Bearer fq_live_..."

curl -X PATCH https://forgequeue.8rec.com/api/public/repos/<repo-id>/testflight/testers \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"add": "tester@example.com"}'

curl "https://forgequeue.8rec.com/api/public/play-console/testers?packageName=com.example.app" \
  -H "Authorization: Bearer fq_live_..."

curl -X PATCH https://forgequeue.8rec.com/api/public/play-console/testers \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"packageName": "com.example.app", "googleGroups": ["testers@example.com"]}'

Filing issues

File a suggestion, feature request, or bug straight from a script or CI job — not a dispute, those need the dashboard's context on a specific charge. type is suggestion, feature_request, or bug; buildId is optional. Each filed issue gets a short key (e.g. B-3) you can reference when following up. Private to your team by default (see below) — pass sharedWithTeam: true to open it up to teammates from the start.

curl -X POST https://forgequeue.8rec.com/api/public/issues \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"type": "suggestion", "title": "...", "body": "..."}'

Reading back a single issue and its full comment thread — including replies on issues filed from the dashboard, not just ones filed through this key. The list endpoint above (GET /api/public/issues) shows the same set of issues this can read individually.

curl https://forgequeue.8rec.com/api/public/issues/<issue-id> \
  -H "Authorization: Bearer fq_live_..."

Editing, sharing, reopening, and commenting

An issue is visible only to whoever filed it until they choose otherwise — sharedWithTeam: true opens it up to the rest of the team (for reading and commenting, not editing); false makes it private again, any time. reopen: true moves a done issue back to incoming — not available once it's been archived, and not for a dispute (those resolve through the dispute flow, not a status flip). title/body can be edited the same way. None of this works on an issue this key didn't file, even one it can otherwise see because it's shared.

curl -X PATCH https://forgequeue.8rec.com/api/public/issues/<issue-id> \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"sharedWithTeam": true}'

curl -X POST https://forgequeue.8rec.com/api/public/issues/<issue-id>/comments \
  -H "Authorization: Bearer fq_live_..." -H "Content-Type: application/json" \
  -d '{"body": "..."}'

10.0 — questions or issues

The Issues tab on your dashboard goes straight to the team behind forgeQueue — report a bug, dispute a charge, or ask for something it doesn't do yet.