What you're filling in
When you click Magic Deploy in LingCode and choose App Store Connect (API key), you'll see four fields. Each comes from a different page on Apple's developer portals — this guide walks through them in the order LingCode shows them.
| Field | What it is | Where to get it |
|---|---|---|
| Key ID | 10-character ID for your API key, e.g. ABC123XYZ0. | App Store Connect → Users and Access → Integrations → Keys |
| Issuer ID | UUID for your team's API integration. | Same Keys page (shown above the table) |
| Team ID | 10-character Apple Developer team ID, e.g. HPTTZS5J27. | Apple Developer → Membership Details |
| .p8 file | Private key Apple generates once when you create the API key. | Downloaded the moment you create the key — saved as AuthKey_<KeyID>.p8 |
Two in-app shortcuts make this easier. Magic Deploy runs a preflight before any xcodebuild call, checking that Xcode (not just Command Line Tools) is selected and that your keychain holds an Apple Distribution certificate matching the Team ID — catching ~70% of first-deploy failures in about a second. And the Auto-bump build number checkbox next to the fields runs agvtool next-version -all before each archive, eliminating the second-most-common failure ("Redundant Binary Upload"). The auto-bump toggle is off by default — tick it the first time you deploy.
Why are there so many pieces? Apple's deploy flow is long because it chains together a trust chain: your Apple ID proves you, your Team ID proves which organization you ship under, your Apple Distribution certificate proves your team holds the private key, the provisioning profile proves the app is allowed to use that cert with those entitlements, and the signed .xcarchive carries that chain all the way to the user's device, which verifies it on every launch. Each field LingCode asks you for plugs into one link of that chain — removing any link breaks the whole thing. Terms unfamiliar? See the glossary.
Before you start — one-time Apple setup
The four fields in Magic Deploy are the final piece. Several things have to already be true on the Apple side, or the upload will fail in ways the UI can't always explain clearly. Walk this checklist once, then you're done for the life of the project.
1. A paid Apple Developer Program membership
A free Apple ID can build and run on your own Mac but cannot upload to App Store Connect. Enroll at developer.apple.com/programs/enroll. It's $99/year for an individual; organizations need a D-U-N-S number and typically take 3–10 business days to be verified. Until your account status shows as Active on developer.apple.com/account, none of the steps below will work.
2. Xcode installed, not just Command Line Tools
LingCode Magic Deploy shells out to xcodebuild, which lives inside the full Xcode app — the standalone Command Line Tools bundle is not enough. Install Xcode from the Mac App Store or developer.apple.com/download, open it once to accept the license, then confirm in Terminal:
xcode-select -p
# should print: /Applications/Xcode.app/Contents/Developer
If it prints /Library/Developer/CommandLineTools instead, point it at Xcode:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept
3. Signed in to Xcode with your developer account
Open Xcode → Settings → Accounts. Click +, pick Apple ID, and sign in with the account that owns your developer membership. The team you want to ship under should appear under your Apple ID row; click it and confirm the Team ID matches the one you'll paste into LingCode.
4. A distribution certificate in your login keychain
xcodebuild signs the archive with a "Apple Distribution" (or legacy "Mac App Distribution") certificate. The easiest way to get one is to let Xcode generate it the first time you archive — but you can also create it yourself:
- Xcode Settings → Accounts → Manage Certificates → + → Apple Distribution. Xcode creates the cert and adds it to your login keychain.
Sanity-check in Terminal:
security find-identity -v -p codesigning | grep -i distribution
You should see a line like 1) 1A2B... "Apple Distribution: Your Name (HPTTZS5J27)". The 10-character code in parentheses is your Team ID — it must match the Team ID field in LingCode.
Certificates are machine-local. If you regenerate a Mac or switch computers, you'll need to either export/import the private key from the old machine's Keychain Access, or create a new certificate and ship from the new machine. Magic Deploy cannot upload from a machine that has no matching private key.
5. An app record in App Store Connect
Apple will not accept uploads for a bundle identifier that doesn't exist yet. Create the record first:
- Sign in at appstoreconnect.apple.com.
- My Apps → + → New App.
- Platforms: tick iOS, macOS, or both — whichever matches the Xcode target you're shipping. Magic Deploy auto-detects from the scheme and picks the right
altool --type. - Bundle ID: pick the identifier that matches your Xcode project's Bundle Identifier exactly (shown in the target's General tab). If it's not in the dropdown, register it first at developer.apple.com/account/resources/identifiers as a Mac App identifier (not iOS).
- SKU: any internal string you'll never reuse. Can't be changed after creation.
com-example-myappis a safe default. - User access: leave as Full Access unless you have a reason to restrict.
The record can be completely unfilled — no screenshots, no description, no pricing — and you still can't submit for review, but you can upload builds to it. That's what Magic Deploy does.
Your Xcode project must have these settings
The Apple side can be perfect and the upload will still fail if the .xcodeproj isn't configured for Mac App Store distribution. Open the target's Signing & Capabilities tab and verify each of these:
Signing & Capabilities
- Automatically manage signing — turned on. Magic Deploy's generated
ExportOptions.plistsetssigningStyletoautomatic, so manual signing will conflict. - Team — set to the same team whose Team ID you'll paste into LingCode. If you see a yellow warning triangle here, click it and resolve (usually just "Add Account").
- Bundle Identifier — matches the app record you created in App Store Connect. Typos (
com.example.MyAppvscom.example.myapp) cause rejections at upload time. - App Sandbox — required for Mac App Store only. Click + Capability if it isn't already there. Enable any entitlements your app actually needs (Network → Outgoing Connections, File Access, etc.) — don't enable everything "just in case", each entitlement is reviewed. (iOS targets skip this — iOS apps are sandboxed by default at the OS level.)
- Hardened Runtime — required for Mac App Store only. Xcode adds this automatically for new macOS targets, but older projects may need to add it by hand. (Not applicable to iOS.)
Version and build numbers
In the target's General tab, under Identity:
- Version (
CFBundleShortVersionString) — the human-facing version, e.g.1.2.3. App Store review cares about this. - Build (
CFBundleVersion) — the internal build number. Must be strictly greater than every build you've previously uploaded for the same Version. If you upload1.2.3 (42), the next upload for1.2.3has to be at least43. Many first-time-with-Magic-Deploy failures are just "I forgot to bump this."
Scheme
LingCode picks the first scheme that xcodebuild -list returns. If your project has multiple schemes (app + tests + a helper target, for example), make sure the one that builds the distributable app comes first — reorder in Xcode → Product → Scheme → Manage Schemes.
Also ensure the scheme is marked Shared in that same dialog. Non-shared schemes live in your personal xcuserdata/ and may not be visible to xcodebuild.
Step 1 — Create an App Store Connect API key
This single step gets you three of the four fields: the Key ID, the Issuer ID, and the .p8 file.
- Sign in at appstoreconnect.apple.com with the Apple ID that owns your developer account.
- In the top nav, click Users and Access.
- Switch to the Integrations tab, then select App Store Connect API in the sidebar (sometimes labelled just Keys).
- Click the + button to generate a new key. Give it a name like "LingCode Magic Deploy" and pick the access level — App Manager is enough to upload builds; use Admin if you also want LingCode to manage app metadata later.
- Click Generate. Apple shows a one-time Download API Key link.
The .p8 file can only be downloaded once. Apple will not let you re-download it. If you lose it, you have to revoke the key and create a new one. Save it somewhere you back up — Documents, iCloud Drive, or a password manager that supports file attachments.
After downloading, the file will be named something like AuthKey_ABC123XYZ0.p8. The 10 characters between AuthKey_ and .p8 are your Key ID. The same Key ID appears in the table on the Keys page; the long UUID at the top of that page (above the table, next to Issuer ID) is your Issuer ID.
Copy these into LingCode
- Key ID → paste into the Key ID field.
- Issuer ID → paste into the Issuer ID field.
- .p8 file → click Browse… in LingCode and pick the file you just downloaded.
Step 2 — Get your Team ID
The Team ID lives on a different site — the Apple Developer portal, not App Store Connect.
- Sign in at developer.apple.com/account with the same Apple ID.
- In the sidebar, click Membership Details (older accounts may show it as just Membership).
- Copy the 10-character Team ID.
If you belong to multiple teams (personal + organization, for example), make sure the team you pick is the one that owns the App Store Connect record for the app you're shipping. The Team ID and the API key must match the same team.
Step 3 — Click Deploy
With all four fields filled and the .p8 selected, the Deploy to App Store button activates. Before we walk through what LingCode actually runs, here's what the manual version of this would look like — it's worth seeing so the automation makes sense.
The typical archive & upload flow (by hand)
If you were shipping this without Magic Deploy, you'd do roughly this sequence in Xcode and App Store Connect:
- Create the app record. In App Store Connect → My Apps → +, create a new app with the same bundle ID as your Xcode project. You can't upload a build to an app that doesn't exist yet.
- Pick the release scheme. In Xcode's scheme dropdown, choose the scheme that builds the distributable target (usually just your app's scheme, in Release configuration — check Product → Scheme → Edit Scheme → Archive).
- Archive. Product → Archive. Xcode builds the release configuration, code-signs with your team's certificate (automatic signing fetches or creates a Distribution profile on the fly), and produces an
.xcarchivebundle in~/Library/Developer/Xcode/Archives/. - Open the Organizer. Xcode jumps to Window → Organizer → Archives automatically when the archive finishes. Pick the archive you just made.
- Validate (optional but recommended). Click Validate App. Xcode talks to App Store Connect to check the archive — missing icons, wrong Info.plist keys, bad entitlements surface here before you spend time uploading.
- Distribute App. Click Distribute App → App Store Connect → Upload. Xcode asks about signing (pick Automatically manage signing), then uploads the archive to App Store Connect. On a good connection this takes 1–5 minutes depending on bundle size.
- Wait for processing. The build lands in App Store Connect in Processing state. Apple's build servers do their own validation, symbolicate crash info, and extract metadata. This takes anywhere from 2 minutes to 30 minutes, outside your control.
- Submit for review or distribute to TestFlight. Once processing finishes, the build is attachable to a new app version (for App Store review) or to a TestFlight group (for internal/external testers).
The tedious parts are steps 3–6: clicking through Xcode, answering the same signing questions every time, and waiting for the Organizer UI to respond. Magic Deploy replaces all of it.
What LingCode Magic Deploy runs instead
Under the hood, the Deploy to App Store button shells out to the same command-line tools Xcode uses. You can see this in your project's build/ directory while it runs. In order:
- Find the project and scheme. LingCode looks in the open project folder for a
.xcodeproj, then runsxcodebuild -list -project <project> -jsonto enumerate schemes and picks the first one. There is no scheme override in the UI — if your project has multiple schemes and the first isn't the right one, reorder them in Manage Schemes in Xcode, or for now archive by hand. - Archive.
The destination (xcodebuild archive \ -scheme <scheme> \ -configuration Release \ -archivePath build/<scheme>.xcarchive \ -destination "generic/platform=macOS"generic/platform=macOSorgeneric/platform=iOS) and the--typeflag onaltoolare chosen automatically from the scheme'sSUPPORTED_PLATFORMS. You'll see[App Store] Detected platform: iOSormacOSin the progress log, so you can confirm before it builds. - Generate
ExportOptions.plist. LingCode writes a three-key plist tobuild/ExportOptions.plist:
That's why the Team ID field matters — it ends up here, and it must match the team that owns the signing certificate installed in your keychain.<key>method</key> <string>app-store</string> <key>teamID</key> <string><your Team ID></string> <key>signingStyle</key> <string>automatic</string> - Export.
This producesxcodebuild -exportArchive \ -archivePath build/<scheme>.xcarchive \ -exportPath build/AppStoreExport \ -exportOptionsPlist build/ExportOptions.plistbuild/AppStoreExport/<scheme>.app, a fully signed and packaged app bundle ready for upload. - Upload.
This is the sameAPI_PRIVATE_KEYS_DIR=<dir with .p8> xcrun altool \ --upload-app \ -f build/AppStoreExport/<scheme>.app \ --type macos \ --apiKey <Key ID> \ --apiIssuer <Issuer ID>altoolthat Xcode's Distribute App → Upload uses internally. The.p8you provided is how it signs JWTs to authenticate against App Store Connect.
Every stdout / stderr line from these commands streams into the progress panel in real time, so when something goes wrong (bad certificate, missing entitlement, App Store Connect validation failure) you see the exact error Xcode would have shown you — without having to click through the Organizer to find it.
On success, the build lands in App Store Connect in Processing. After Apple's processing finishes (2–30 minutes, outside LingCode's control), it shows up under TestFlight → Builds and is ready to submit for review or distribute to testers.
Reading the progress log
While Magic Deploy runs, the right-hand panel streams the live output of xcodebuild and xcrun altool. Everything LingCode prefixes with [App Store] is a status marker from LingCode itself; everything else is verbatim output from Apple's tools.
A successful run looks roughly like this, end-to-end:
[App Store] Archiving...
Build settings from command line:
...
ArchiveSucceeded
[App Store] Writing ExportOptions.plist...
[App Store] Exporting...
ExportArchive: signing
ExportArchive: writing /…/build/AppStoreExport/MyApp.app
[App Store] Uploading...
*** Upload Progress: ...
No errors uploading '…/MyApp.app'.
[App Store] Upload complete. Check App Store Connect for the new build.
Where to look when things break: scroll to the very end of the log. xcodebuild prints warnings all the way through the build — the real error is almost always in the last 20 lines, usually after the line that begins ** ARCHIVE FAILED **, ** EXPORT FAILED **, or *** Error: .... LingCode's short "Archive failed. Check the log above." message is just a pointer; the diagnostic detail is in the raw output.
Per-phase troubleshooting
Group failures by which phase they happen in — the fix path is different in each.
Archive phase (xcodebuild archive)
This is where most first-time errors surface, because it's the first time your project is actually being built for Release with real signing.
| Log contains | Why | Fix |
|---|---|---|
| No signing certificate "Apple Distribution" found | No distribution cert in your keychain, or the one you have belongs to a different team. | Xcode → Settings → Accounts → Manage Certificates → + → Apple Distribution. Then re-run Deploy. |
| No profiles for 'com.example.app' were found | Automatic signing couldn't create or fetch a provisioning profile for this bundle ID, usually because the bundle ID isn't registered at developer.apple.com. | Register the bundle ID at developer.apple.com/account/resources/identifiers (as Mac App), then retry. |
| Provisioning profile doesn't include the current device | You have manual signing turned on with a wrong profile. | Signing & Capabilities → turn Automatically manage signing back on. |
| Command PhaseScriptExecution failed with a nonzero exit code | A Run Script build phase (CocoaPods, SwiftLint, SwiftGen, etc.) errored out. | Open the target's Build Phases tab in Xcode, find the failing script, and read its actual error in the log lines just above. |
Swift compile errors (error: …) |
Your code doesn't compile in Release — commonly due to #if DEBUG branches or conditional imports. |
In Xcode, switch the scheme's Run configuration to Release and build locally until it compiles. |
| Missing required architecture x86_64 | Your project isn't building a universal binary. Mac App Store accepts Apple Silicon-only, but mixed setups often fail here. | Target → Build Settings → Architectures → set to $(ARCHS_STANDARD). Remove any hard-coded arm64-only overrides. |
| The archive was not created | Scheme doesn't have an Archive action enabled, or the Archive build configuration isn't set to Release. | Product → Scheme → Edit Scheme → Archive tab → Build Configuration: Release, and make sure the app target is ticked. |
Export phase (xcodebuild -exportArchive)
| Log contains | Why | Fix |
|---|---|---|
| error: exportArchive: No "Apple Distribution" signing certificate matching team ID | The teamID in the generated ExportOptions.plist doesn't match any cert in your keychain. |
Fix the Team ID field in Magic Deploy. Run security find-identity -v -p codesigning — the 10-char code in parentheses is the one to paste. |
| error: Provisioning profile "…" doesn't include the entitlement com.apple.security.app-sandbox | App Sandbox isn't enabled on the target but Mac App Store requires it. | Signing & Capabilities → + Capability → App Sandbox. |
| error: Provisioning profile "…" doesn't include the hardened runtime | Hardened Runtime not enabled for the Release config. | Signing & Capabilities → + Capability → Hardened Runtime, or set ENABLE_HARDENED_RUNTIME = YES in Build Settings. |
| error: No matching profiles found for bundle identifier … | Automatic signing can generate the profile for Development but not for Distribution — often because the App Store Connect app record doesn't exist yet. | Create the app record in App Store Connect (see Before you start step 5). Re-run Deploy. |
Upload phase (xcrun altool --upload-app)
| Log contains | Why | Fix |
|---|---|---|
| Unable to find API key with Key ID … | altool couldn't find AuthKey_<KeyID>.p8 in the directory you picked. |
Re-select the .p8 file in Magic Deploy, and make sure its filename is exactly AuthKey_<KeyID>.p8. Renaming it will break altool. |
| Authentication credentials are missing or invalid (HTTP 401) | Key ID, Issuer ID, or the .p8 don't match. |
Copy the Key ID and Issuer ID directly off the Keys page in App Store Connect — don't retype. Issuer ID is a UUID (with dashes); Key ID is 10 alphanumerics. |
| Forbidden / ITMS-90166 | The API key doesn't have upload permission. | In App Store Connect → Users and Access → Integrations, edit the key and set role to App Manager or Admin. Developer is read-only. |
| ERROR ITMS-90189: "Redundant Binary Upload" | You're uploading a build number that's already on Apple's servers for this version. | Bump the Build field in Xcode (target → General → Build) and re-archive. |
| ERROR ITMS-90035: "Invalid Signature" | The signed app fails Apple's codesign verification — usually a nested framework signed with a development cert, or a helper tool missing its own signature. | Check Signing & Capabilities → Frameworks on the target; make sure every embedded framework says Embed & Sign. For helper tools, add an Embed & Sign Copy Files phase. |
| ERROR ITMS-90338: "Non-public API usage" | A framework (often an analytics SDK) links against a private Apple API. | Update the offending SDK, or remove it. Apple lists the specific symbol in the error message. |
| ERROR ITMS-90713: "Missing Info.plist value" | A required key like NSCameraUsageDescription or LSApplicationCategoryType is missing. |
Add the key to your target's Info.plist. Apple's error message names exactly which key. |
| The network connection was lost / timed out | Flaky upload. Large bundles over slow connections time out the 600-second budget. | Retry. If it keeps failing, run the xcrun altool command from the log directly in Terminal — altool will show a richer progress indicator and can sometimes resume. |
What happens after a successful upload
When Magic Deploy finishes, the build is in App Store Connect → your app → TestFlight → macOS → Builds, initially in Processing state. Apple's build servers run their own post-upload validation — symbolicating crash info, scanning for private API usage, extracting metadata. This usually takes 5–30 minutes but can stretch to an hour or more at peak times. You'll get an email when processing finishes (or when it fails with an ITMS- error).
Once processing is done, you have two paths:
- TestFlight — attach the build to an internal or external test group to distribute to testers. Internal testers (up to 100 users with App Store Connect access) get it immediately. External testers require a brief Beta App Review (usually under 24h for minor updates).
- Submit for review — attach the build to a new app version under the macOS App section, fill in the required metadata (description, screenshots, pricing, privacy), and click Add for Review. Review typically takes 24–72 hours for macOS apps.
If the build never shows up at all — not even in Processing — check the email associated with your Apple ID. Apple sends rejection emails (ITMS-90xxx codes) for binaries that failed server-side validation, and those rejected builds don't appear in App Store Connect at all.
Quick reference: where to go when something's wrong
| Symptom | Where to fix |
|---|---|
| Magic Deploy button stays disabled | One of the four fields is empty, or the .p8 file isn't attached. LingCode validates all four before enabling the button. |
| "No Xcode project found" | You opened a folder that doesn't contain a .xcodeproj. Open the folder that does, or the .xcodeproj itself. |
| "No schemes found" | Your schemes aren't marked Shared. Xcode → Product → Scheme → Manage Schemes → tick Shared on the one you want to build. |
| Archive phase fails | Open Xcode, switch to the Release configuration, and do Product → Archive yourself. Fix whatever Xcode complains about, then retry Magic Deploy. |
| Export phase fails | 99% of the time it's the ExportOptions.plist teamID not matching your keychain. Run security find-identity -v -p codesigning and fix the Team ID field in LingCode. |
| Upload phase fails with HTTP 401/403 | Problem is the API key. Re-download the .p8, or create a fresh key with App Manager role and try again. |
| Upload succeeds but build never appears | Check the email on your Apple ID for an ITMS- rejection. If nothing, wait 30 minutes — Apple's processing queue varies. |
| "Redundant binary upload" | Bump the Build number in Xcode. Any integer greater than the previous one. |
| Still stuck | Copy the exact xcodebuild or xcrun altool command from the log and run it in Terminal — the error messages are identical and easier to Google than "Archive failed. Check the log above.". |
Common mistakes (quick checklist)
- Renaming the
.p8file. LingCode looks forAuthKey_<KeyID>.p8. If you renamed it, either rename it back or make sure the Key ID field matches whatever is betweenAuthKey_and.p8in the filename. - Wrong access level. A Developer-level key can read but not upload. You need App Manager or Admin.
- Issuer ID vs Key ID confusion. Key ID is 10 characters and shown per-key in the table. Issuer ID is a long UUID (with dashes) shown once at the top of the Keys page.
- Team ID from the wrong team. If your Apple ID is on multiple teams, switch teams in the developer portal first to make sure you copy the right one.
- Bundle ID not registered. The app's bundle identifier needs an App Store Connect record, and the identifier itself needs to exist in Certificates, IDs & Profiles at developer.apple.com. Create the app record in App Store Connect → My Apps → + first, using the same bundle ID as your Xcode project.
- Forgetting to bump Build. Every upload for the same Version needs a higher Build number. This is the single most common cause of second-upload failures — tick Auto-bump build number in the pane to have LingCode run
agvtool next-version -allfor you. - Manual signing turned on. Magic Deploy's
ExportOptions.plistusessigningStyle = automatic. If your target has manual signing on, the export will fail or produce an unsignable binary.
Security notes
The .p8 private key is the equivalent of a password for your App Store Connect account. Treat it that way: don't commit it to git, don't share it in Slack, and revoke it from the Keys page if a teammate leaves or a laptop is lost. LingCode never uploads the .p8 anywhere — it stays on your Mac and is only handed to Apple's xcrun altool at upload time.
Further reading
Primary sources for the concepts on this page, from Apple and the IETF:
- LingCode deploy glossary — every term on this page, defined.
- App Store Connect API reference (Apple) — what
altooland LingCode talk to under the hood. - Distributing your app for beta testing and releases (Apple) — official Xcode distribution guide.
- Code Signing Guide (Apple) — deep dive on certs, profiles, and what signing actually proves.
- RFC 7519 — JSON Web Token — the JWT spec Apple's API uses for auth.
- TestFlight (Apple) — the beta service your uploads land in first.
Ready to ship?
See the full Magic Deploy feature set, or read about slash commands and multi-session Claude workflows.
Download LingCode for Mac