flowdeck ship needs two things: an App Store Connect
account FlowDeck can authenticate as, and a repository that knows which app
record it belongs to. This page covers both.
One stored credential, and two ways to get one
The only credential FlowDeck stores is an App Store Connect API key, kept in your login keychain. You can create one yourself in App Store Connect, or mint one through an Apple Account sign-in — either way, what ends up stored is the same kind of key. That is deliberate. An Apple ID gives away your entire Apple account; an API key is scoped to App Store Connect, revocable on its own, and documented, so it does not break when Apple changes something private. Create one in App Store Connect under Users and Access › Integrations, and download the.p8 file. Apple lets you download it once.
Connecting an account
The key is checked against Apple before anything is stored. A key that cannot
authenticate, or that lacks permission to read apps, is refused rather than
saved for you to discover later.
There is no
--team-id. An API key belongs to exactly one account, and that
account is exactly one team, so FlowDeck derives the Developer Team ID itself.More than one account
Credentials are keyed by issuer ID, so a machine can hold as many as you have..flowdeck/config.json. It is
never inferred: two accounts can share a team, and the cost of guessing wrong
is a build pushed to somebody else’s listing.
If several accounts are connected and the repository has not chosen one,
commands fail with shipAmbiguousAccount rather than picking for you.
Checking an account
isAdmin reports whether this key can create app records in App Store
Connect, which is an Admin-only action on the web. It is a Bool?: absent
means the check could not be made, not that you lack the permission.
Removing an account
Apple web session
A handful of operations — minting a new API key, or creating a new app record automatically — are not exposed by App Store Connect’s API at all, only by the same web session the Apple Account website itself uses.flowdeck ship auth apple wraps that session for exactly those cases; most
ship commands never need it.
shipAppleSecureInputUnavailable instead of accepting visible secret input.
Noninteractive callers can provide the password and, when requested, the code
as successive lines on stdin. The password is passed to Apple’s own sign-in
tooling through an environment variable; FlowDeck never logs it, stores it,
or returns it in any output or error. Apple stores the resulting session in
the Mac’s login keychain, the same way signing in through a browser would.
If Apple asks for a two-factor code, login pauses and prints
{"stage":"AWAIT_2FA"} on its progress stream under --json (a plain
sentence in text mode); enter the code at the hidden prompt on the same stdin.
Can this account mint a key?
Minting a key requires the Account Holder or Admin role. Check first, read-only and offline:roleCheck is one of three states, not two: accountHolderOrAdmin,
insufficientRole, or unreadable. unreadable means the response could not
be parsed — it is not evidence the account lacks the role, only that this
could not tell, and it is a normal answer with exit code 0. No session at all
is different: it fails with shipAppleMintKeyNoSession and a non-zero exit,
because there is nothing to ask.
Minting a key
mint-key checks the role above before creating anything: an
insufficientRole or unreadable account is refused up front rather than
failing partway through. On success, the new key is imported the same way
auth add stores a pasted one, so it appears in auth list immediately.
Linking a project to an app
An account can reach many apps. Linking records which one this repository ships to, in a small git-tracked file so the whole team inherits it.--all-accounts tags each row
with its issuer, so you do not have to know which account holds which app
before you can pick one.
Where a project stands
currentVersion is the newest version in any state; liveVersion is the
newest one on sale. They are equal when nothing new is in flight, and
liveVersion is absent for a platform that has never shipped.
When the app record does not exist yet
Apple does not allow creating an app record through the public API, for any key. With a live Apple Account session (--apple-session auto, the default),
app init creates the record directly through that session instead. Without
one, or when Apple clearly refuses the direct attempt, it falls back to the
guided web form, exactly as it always has:
--name always takes this path too, live
session or not: inventing one would create a real, permanently-SKU’d record
under a name nobody chose.
If the direct attempt fails and the guided fallback also gives up waiting, the
command reports shipDirectAppCreateFailed: the bundle ID is already
registered, so nothing is lost, and the fix is
flowdeck ship app link --bundle-id com.example.myapp once the record exists.
An exit-zero create with an unreadable response is different: Apple may have
created the record already. FlowDeck polls by bundle ID for a bounded period
and links the record if it appears. If it does not, the command reports
shipAppCreateResultAmbiguous and tells you to check and link the existing
record; it never opens or recommends the create form again. Do not run
ship app init again after this uncertain result. Check App Store Connect,
then finish with flowdeck ship app link --bundle-id com.example.myapp once
the record is visible.

