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

> Learn how the ipatool download command resolves bundle identifiers and external version IDs. Understand the two stage process of mapping IDs and selecting app versions for efficient downloads.

- Repository: [Majd/ipatool](https://github.com/majd/ipatool)
- Tags: internals
- Published: 2026-09-06

---

**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](https://github.com/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`](https://github.com/majd/ipatool/blob/main/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`](https://github.com/majd/ipatool/blob/main/cmd/download.go), the command constructs a `LookupInput` and delegates to the `AppStore` interface:

```go
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`](https://github.com/majd/ipatool/blob/main/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`:

```go
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`](https://github.com/majd/ipatool/blob/main/cmd/download.go):

```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`](https://github.com/majd/ipatool/blob/main/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`](https://github.com/majd/ipatool/blob/main/cmd/download.go) (lines 24‑28) | Extracts `app-id`, `bundle-identifier`, `external-version-id`, `platform` |
| Platform validation | [`cmd/download.go`](https://github.com/majd/ipatool/blob/main/cmd/download.go) (line 38) | `appstore.ParsePlatform` validates platform string |
| Bundle resolution | [`cmd/download.go`](https://github.com/majd/ipatool/blob/main/cmd/download.go) (lines 71‑82) | `store.Lookup` → [`appstore_lookup.go`](https://github.com/majd/ipatool/blob/main/appstore_lookup.go) → App Store API |
| License acquisition | [`cmd/download.go`](https://github.com/majd/ipatool/blob/main/cmd/download.go) (lines 84‑99) | Optional `store.Purchase` if `--purchase` flag set |
| Package download | [`cmd/download.go`](https://github.com/majd/ipatool/blob/main/cmd/download.go) (lines 23‑31) | `store.Download` → [`appstore_download.go`](https://github.com/majd/ipatool/blob/main/appstore_download.go) with version ID |
| Post‑processing | [`cmd/download.go`](https://github.com/majd/ipatool/blob/main/cmd/download.go) (lines 84‑89) | Optional SINF replication for macOS |

## Practical Usage Examples

```bash

# 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`](https://github.com/majd/ipatool/blob/main/cmd/download.go) | CLI command implementation, orchestrates lookup and download flows |
| [`pkg/appstore/appstore_lookup.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_lookup.go) | `Lookup` function – bundle identifier → internal App ID translation |
| [`pkg/appstore/appstore_download.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_download.go) | `Download` function – handles external version ID and fetches IPA |
| [`pkg/appstore/appstore.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore.go) | `AppStore` interface definition (`Lookup`, `Download`, `Purchase`, etc.) |
| [`pkg/appstore/platform.go`](https://github.com/majd/ipatool/blob/main/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`](https://github.com/majd/ipatool/blob/main/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.