# How to List Purchased Apps Using IPATool: Command Guide and Implementation

> Easily list all purchased apps from your Apple App Store account with the IPATool list purchases command. Learn how to implement and use pagination for large libraries.

- Repository: [Majd/ipatool](https://github.com/majd/ipatool)
- Tags: how-to-guide
- Published: 2026-08-31

---

**Use the `ipatool list-purchases` command to retrieve all apps associated with your authenticated Apple App Store account, with optional pagination flags to handle large libraries.**

IPATool is a command-line interface for interacting with the Apple App Store, maintained in the [majd/ipatool](https://github.com/majd/ipatool) repository. The `list-purchases` command provides direct access to your complete purchase history by implementing the private App Store DAAP protocol. This guide explains the command syntax, pagination options, and the underlying architecture that powers the feature.

## Prerequisites: Authentication Requirements

Before listing purchased apps, you must authenticate with the Apple App Store. IPATool stores account credentials securely and handles token refresh automatically when running `list-purchases`.

Run the authentication command first:

```bash
ipatool auth login

```

The tool caches your **password token** locally. If the token expires during a `list-purchases` request, IPATool automatically re-authenticates using your stored credentials before fetching the app list.

## Basic Command Syntax

The `list-purchases` subcommand retrieves owned apps with minimal configuration:

```bash
ipatool list-purchases

```

By default, this returns the first page of results using the `appstore.DefaultOwnedAppsLimit` defined in the source constants. Each app entry includes the **bundle ID**, **name**, **version**, and **purchase date**.

## Pagination Controls

For accounts with large purchase histories, IPATool provides two flags to navigate results efficiently.

### The `--page` Flag

Specify which page of results to retrieve using the `-p` or `--page` flag:

```bash
ipatool list-purchases --page 3

```

The validation logic in [`cmd/purchases.go`](https://github.com/majd/ipatool/blob/main/cmd/purchases.go) enforces that page values must be **greater than or equal to 1**.

### The `--max-results` Flag

Control the number of apps returned per request using `-l` or `--max-results`:

```bash
ipatool list-purchases --page 2 --max-results 50

```

This value must be **at least 1** and cannot exceed `appstore.MaxOwnedAppsLimit`. If you request more than the maximum allowed, the command fails validation before making any network requests.

## How the List Purchases Command Works

The `list-purchases` implementation spans multiple packages in the IPATool codebase. Understanding this flow helps troubleshoot issues and extends the tool's functionality.

### CLI Initialization and Validation

The command entry point resides in [[`cmd/purchases.go`](https://github.com/majd/ipatool/blob/main/cmd/purchases.go)](https://github.com/majd/ipatool/blob/main/cmd/purchases.go). The `listPurchasesCmd()` function constructs a `cobra.Command` with the two pagination flags and defines a `PreRunE` hook that validates:

- The `page` parameter is ≥ 1
- The `max-results` parameter is ≥ 1 and ≤ `appstore.MaxOwnedAppsLimit`

If validation fails, the command exits before making network calls.

### Account Authentication Flow

During execution, the command first calls `dependencies.AppStore.AccountInfo()` to retrieve stored credentials. If the password token has expired (`appstore.ErrPasswordTokenExpired`), the system automatically invokes `AppStore.Login` using the cached email and password pair. This retry logic ensures uninterrupted access without manual re-authentication.

### The Owned Apps API Implementation

The core retrieval logic lives in [[`pkg/appstore/appstore_owned_apps.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_owned_apps.go)](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_owned_apps.go). The `OwnedApps` method executes a complex sequence to interface with Apple's private APIs:

1. **Input normalization** via `normalizeOwnedAppsInput` to standardize pagination parameters
2. **Machine identity generation** creating a GUID-based machine ID for the request
3. **SAP configuration retrieval** to build an authenticated action signer
4. **DAAP endpoint communication** through three sequential operations:
   - `ownedAppsLoginRequest` opens a purchase history session
   - `ownedAppsUpdateRequest` retrieves the latest revision token
   - `ownedAppsItemsRequest` fetches the actual app data for the requested page
5. **Response parsing** via `parseOwnedApps` converting raw DMAP responses into structured `App` structs

Each `App` struct, defined in [`pkg/appstore/app.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/app.go), contains the ID, bundle identifier, name, version string, and purchase timestamp.

### Pagination and Output Processing

After retrieving the complete owned apps list, the system:

1. Sorts results by purchase date using `ownedAppsSortedByPurchaseDate`
2. Slices the array to the requested page using `ownedAppsPage`
3. Returns an `OwnedAppsOutput` struct containing the count, total count, page number, and results slice

The command outputs this data through the structured logger (`dependencies.Logger`), displaying the paginated app list in the terminal.

## Practical Examples

### List First Page with Default Settings

Retrieve the most recent purchases using default pagination:

```bash
ipatool list-purchases

```

### Navigate Large Purchase Histories

Retrieve older purchases by incrementing the page number and increasing page size:

```bash
ipatool list-purchases --page 5 --max-results 100

```

### Programmatic Integration

The following Go excerpt demonstrates how the command constructs the `OwnedAppsInput` struct and handles the API response, based on the implementation in [`cmd/purchases.go`](https://github.com/majd/ipatool/blob/main/cmd/purchases.go):

```go
out, err := dependencies.AppStore.OwnedApps(appstore.OwnedAppsInput{
    Account: info.Account,
    Page:    page,
    Limit:   maxResults,
})
if err != nil {
    return err
}

dependencies.Logger.Log().
    Int("count", out.Count).
    Int("total", out.Total).
    Array("apps", appstore.Apps(out.Results)).
    Send()

```

This pattern allows developers to integrate purchase listing into custom automation tools using IPATool's underlying packages.

## Summary

- **Command location**: Defined in [`cmd/purchases.go`](https://github.com/majd/ipatool/blob/main/cmd/purchases.go) as `listPurchasesCmd()`
- **Core implementation**: Resides in [`pkg/appstore/appstore_owned_apps.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_owned_apps.go) via the `OwnedApps` method
- **Pagination**: Controlled via `--page` (default 1) and `--max-results` flags, bounded by `MaxOwnedAppsLimit`
- **Authentication**: Automatic token refresh when `ErrPasswordTokenExpired` occurs during execution
- **Data returned**: Array of `App` structs containing bundle ID, name, version, and purchase date

## Frequently Asked Questions

### Do I need to log in before using list-purchases?

Yes. IPATool requires a valid Apple App Store authentication token. Run `ipatool auth login` first to store credentials. If your token expires during a `list-purchases` execution, the tool automatically re-authenticates using the stored password.

### What is the maximum number of apps I can retrieve per page?

The maximum is defined by `appstore.MaxOwnedAppsLimit` in the source code. The `--max-results` flag must be between 1 and this limit. The exact value is enforced in the pre-run validation within [`cmd/purchases.go`](https://github.com/majd/ipatool/blob/main/cmd/purchases.go).

### How does IPATool handle expired authentication tokens?

When `dependencies.AppStore.AccountInfo()` returns `appstore.ErrPasswordTokenExpired`, the command automatically invokes `AppStore.Login` with the cached account credentials. This retry mechanism is wrapped in the command's execution flow, so users do not need to manually re-authenticate.

### Can I export the purchased apps list to a file?

While `list-purchases` outputs to stdout, you can redirect the output to a file using shell redirection. The tool does not currently support native JSON export flags, but the structured logger output can be piped to `jq` or similar tools for parsing.