How the ipatool Download Command Resolves Bundle Identifiers and External Version IDs

The ipatool download command uses a two‑stage resolution process: it maps bundle identifiers to internal App Store IDs via a lookup API call, and passes external version IDs directly to the download endpoint to select specific app versions.

This article explains how majd/ipatool translates human‑readable app identifiers into the precise values Apple's servers require. Whether you're downloading by bundle ID (com.example.myapp) or targeting a specific build with an external version ID, the resolution logic lives in the cmd/download.go orchestration layer and the pkg/appstore implementation files.

Bundle Identifier Resolution Process

When you supply --bundle-identifier (-b), ipatool cannot use that string directly with Apple's download API. Instead, it must first obtain the numeric internal App ID that Apple's servers recognize.

The Lookup Request

In cmd/download.go, the command constructs a LookupInput and delegates to the AppStore interface:

lookupResult, err := store.Lookup(appstore.LookupInput{
    Account:  acc,
    BundleID: bundleID,
    Platform: platform,
})

This call hits the App Store "lookup" endpoint implemented in pkg/appstore/appstore_lookup.go. The endpoint returns metadata for the matching app, including its internal numeric ID.

Extracting the App ID

The lookupResult.App field (type appstore.App) contains the resolved ID:

app := lookupResult.App
// app.ID now holds the internal App Store identifier

This numeric ID is required for all subsequent operations including store.Download and store.Purchase. The lookup effectively bridges the gap between user‑friendly bundle identifiers and Apple's internal app catalog.

External Version ID Handling

The --external-version-id flag allows targeting specific app versions—beta builds, older releases, or regional variants—without relying on the default "latest" selection.

Passing the Version ID

The external version ID flows directly from CLI flag to download input in cmd/download.go:

out, err := store.Download(appstore.DownloadInput{
    Context:           cmd.Context(),
    Account:           acc,
    App:               app,
    OutputPath:        outputPath,
    Progress:          progress,
    ExternalVersionID: externalVersionID,  // from --external-version-id
    Platform:          platform,
})

Version Selection Logic

Inside pkg/appstore/appstore_download.go, the Download implementation inspects ExternalVersionID:

  • Empty value: Requests the latest available version for the resolved app ID
  • Non‑empty value: Includes the identifier in the download request, causing Apple's servers to return that specific build

This design decouples version selection from app identification. You can combine bundle ID lookup with precise version targeting, or use a numeric app ID directly to bypass lookup entirely.

Complete Download Flow

Step Component Key Operation
Flag parsing cmd/download.go (lines 24‑28) Extracts app-id, bundle-identifier, external-version-id, platform
Platform validation cmd/download.go (line 38) appstore.ParsePlatform validates platform string
Bundle resolution cmd/download.go (lines 71‑82) store.Lookup → appstore_lookup.go → App Store API
License acquisition cmd/download.go (lines 84‑99) Optional store.Purchase if --purchase flag set
Package download cmd/download.go (lines 23‑31) store.Download → appstore_download.go with version ID
Post‑processing cmd/download.go (lines 84‑89) Optional SINF replication for macOS

Practical Usage Examples


# Download latest version by bundle identifier

ipatool download -b com.example.myapp -o MyApp.ipa

# Download specific beta version using external version ID

ipatool download -b com.example.myapp --external-version-id 1234567890 -o MyAppBeta.ipa

# Skip bundle lookup with explicit numeric App Store ID

ipatool download -i 12345678 -o MyApp.ipa

# Combine with platform targeting

ipatool download -b com.example.myapp --platform iphone -o MyApp.ipa

Key Source Files

File Responsibility
cmd/download.go CLI command implementation, orchestrates lookup and download flows
pkg/appstore/appstore_lookup.go Lookup function – bundle identifier → internal App ID translation
pkg/appstore/appstore_download.go Download function – handles external version ID and fetches IPA
pkg/appstore/appstore.go AppStore interface definition (Lookup, Download, Purchase, etc.)
pkg/appstore/platform.go Platform string parsing (iphone, ipad, appletv, visionos, macos)

Summary

  • Bundle identifiers require an API lookup to obtain the internal numeric App ID used by Apple's servers
  • External version IDs pass through unchanged, enabling precise version selection without additional resolution steps
  • The AppStore interface in pkg/appstore/appstore.go abstracts both operations behind a clean Go API
  • Platform validation occurs early, ensuring consistent behavior across iOS, iPadOS, tvOS, visionOS, and macOS targets

Frequently Asked Questions

What happens if I provide both --app-id and --bundle-identifier?

The command uses the numeric app-id directly and skips the lookup step. Bundle identifier resolution only occurs when --app-id (-i) is omitted. This avoids an unnecessary API call when you already know the internal identifier.

Can I use external version IDs without a bundle identifier?

Yes. If you provide --app-id along with --external-version-id, the command bypasses bundle lookup entirely and passes both values to the download endpoint. This is useful for automation workflows that operate on cached app IDs.

Where does the external version ID come from?

External version IDs are assigned by Apple and exposed through the App Store's internal APIs—often visible in enterprise MDM systems, TestFlight metadata, or historical download logs. They represent specific builds rather than marketing version strings like "2.1.0".

Does platform selection affect bundle identifier resolution?

Yes. The same bundle identifier may map to different internal App IDs across platforms (e.g., iPhone vs. iPad variants of the same app). The platform parameter in the lookup request ensures you receive the correct app metadata for your target device family.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →