# How Pagination Works for Owned Apps in ipatool Using `--page` and `--max-results`

> Discover how ipatool pagination works for owned apps. Learn to use --page and --max-results to control API requests and fetch data efficiently.

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

---

**Pagination in ipatool's `owned-apps` command works by converting user-provided `--page` and `--max-results` flags into App Store Connect API `limit` and `offset` query parameters, where `offset = page × max-results`.**

The tool fetches apps from the authenticated Apple developer account through paginated API requests. Understanding this mechanism helps you efficiently browse large app portfolios without hitting rate limits or memory constraints.

## Command-Line Interface

The `owned-apps` subcommand exposes two flags that map directly to API pagination controls:

| Flag | Default | Description |
|------|---------|-------------|
| `--page` | `0` | Zero-based page index |
| `--max-results` | `200` | Maximum apps per request (API ceiling) |

These flags are registered in [`cmd/owned_apps.go`](https://github.com/majd/ipatool/blob/main/cmd/owned_apps.go) and passed to the AppStore implementation.

```bash

# Fetch first 50 apps (page 0)

ipatool owned-apps --max-results 50

# Fetch apps 51-100 (page 1, 50 per page)

ipatool owned-apps --page 1 --max-results 50

```

## API Parameter Mapping

In [`pkg/appstore/appstore_owned_apps.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_owned_apps.go), the `GetOwnedApps()` method transforms CLI flags into App Store Connect query parameters:

- **`limit`** ← `--max-results` — caps the number of returned resources
- **`offset`** ← `--page` × `--max-results` — skips N records from the start

The constructed request URL follows this pattern:

```go
// From pkg/appstore/appstore_owned_apps.go
url := fmt.Sprintf(
    "%s/v1/apps?limit=%d&offset=%d",
    baseURL,
    maxResults,
    page*maxResults,
)

```

## Implementation Details

### Request Building

The [`appstore_owned_apps.go`](https://github.com/majd/ipatool/blob/main/appstore_owned_apps.go) file contains the core pagination logic. The `OwnedAppsInput` struct captures user input:

```go
type OwnedAppsInput struct {
    Page        int
    MaxResults  int
    // ... other fields
}

```

The `GetOwnedApps` function validates bounds, applies defaults from [`pkg/appstore/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/constants.go), and executes the HTTP request through [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go).

### Response Handling

The App Store Connect API returns a JSON:API response with:

- **`data`** — array of app resources for the current page
- **`links.next`** — URL for the subsequent page (omitted on final page)

`ipatool` does **not** auto-paginate by default. Each `--page` value triggers exactly one API call. The caller must increment `--page` manually or script successive invocations.

### Default Limits

As defined in [`pkg/appstore/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/constants.go):

- **Maximum `max-results`**: `200` (App Store Connect API hard limit)
- **Default `max-results`**: `200` when flag is omitted

## Practical Examples

### Browse All Apps Programmatically

```bash
#!/bin/bash
PAGE=0
while true; do
    RESULTS=$(ipatool owned-apps --page $PAGE --max-results 100 --format json)
    COUNT=$(echo "$RESULTS" | jq '.data | length')
    
    echo "$RESULTS" | jq '.data[] .attributes.name'
    
    [ "$COUNT" -lt 100 ] && break  # Last page detected

    ((PAGE++))
done

```

### Combine with Filters

```bash

# Search owned apps by name with pagination

ipatool owned-apps --filter "name:MyApp" --page 0 --max-results 20

```

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`pkg/appstore/appstore_owned_apps.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/appstore_owned_apps.go) | Implements `GetOwnedApps()`, parameter mapping, URL construction |
| [`cmd/owned_apps.go`](https://github.com/majd/ipatool/blob/main/cmd/owned_apps.go) | CLI flag registration, command wiring |
| [`pkg/appstore/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/constants.go) | Default pagination limits, API endpoint constants |
| [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) | HTTP execution, authentication header injection |

## Summary

- **Zero-based paging**: `--page 0` returns the first batch of results
- **Offset calculation**: `offset = page × max-results` happens internally
- **Single request per call**: No automatic pagination; script multiple invocations for full enumeration
- **200-item ceiling**: The API and tool enforce this maximum regardless of higher `--max-results` values
- **Consistent pattern**: Other list commands in `ipatool` reuse this same `limit`/`offset` mechanism

## Frequently Asked Questions

### What happens if I request `--page 5` but there are only 3 pages of results?

The App Store Connect API returns an empty `data` array and no `links.next`. `ipatool` displays zero results without error. Check response metadata to detect out-of-bounds pages.

### Can I use `--max-results` values above 200?

Values exceeding 200 are accepted at the CLI but capped by the API. The [`pkg/appstore/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/appstore/constants.go) file defines `MaxOwnedAppsPerPage = 200`, and the API silently truncates larger requests.

### Does ipatool support cursor-based pagination?

No. According to the implementation in [`appstore_owned_apps.go`](https://github.com/majd/ipatool/blob/main/appstore_owned_apps.go), `ipatool` uses traditional offset/limit pagination. The `links.next` URLs in API responses are not automatically followed; manual `--page` increments are required.

### How do I count total owned apps without fetching all pages?

The App Store Connect API does not return a total count in the `apps` endpoint response. You must paginate through results until receiving an empty `data` array, then sum retrieved items.