Skip to content

About

Production-ready CLI for Apple Search Ads API

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

appleads CLI

appleads

A powerful CLI for Apple Search Ads
Scriptable · Multi-account · CI-friendly · JSON-first

Beta Quickstart Go Install API v5 Safe Mutations License


⚠️ Status

This project is in public beta. Core functionality (auth, campaigns, reports, keyword management) has been tested against live Apple Search Ads accounts. However, not all API endpoints and edge cases have been fully validated. Use in production at your own discretion and please open an issue if you encounter any problems.


✨ Why appleads?

Stop clicking through dashboards. Start shipping campaigns from your terminal.

🚀 Full campaign control Create, update, pause, and report — all from one binary
👥 Multi-account ready Named profiles for agencies and multi-org operators
🛡️ Safe mutations --dry-run, interactive confirms, --yes for CI pipelines
📊 JSON-first output Pipe into jq, feed scripts, build dashboards
🔌 Escape hatch Hit any endpoint with appleads api — no wrapper needed

📦 Installation

Option 1 — Homebrew (recommended)
brew tap FerdiKT/tap
brew install appleads
Option 2 — Go install
go install github.com/ferdikt/appleads-cli@latest
Option 3 — Build from source
git clone https://github.com/FerdiKT/appleads-cli.git
cd appleads-cli
make tidy
make build VERSION=1.1.0
./bin/appleads version
Option 4 — Multi-arch release binaries
make dist VERSION=1.1.0
ls dist/

See docs/RELEASE.md for full release workflow.


🚀 Quickstart

📋 First time with Apple Ads API? Follow the API Setup Guide for the current OAuth flow: pick the right Apple Ads user, generate a key pair, upload the public key, collect clientId/teamId/keyId, then create a token.

Get up and running in 5 minutes.

1️⃣ Initialize auth

What this actually means:

  1. Use an Apple Ads login that can access the target account or campaign groups. In practice this is usually a separate Apple ID invited as the API user, not the primary admin login.
  2. Generate a local private/public key pair.
  3. Upload the public key in Apple Ads to generate clientId, teamId, and keyId.
  4. Save those values locally and mint a token.

When Apple shows the credentials, you can paste the full 3-line block directly into the wizard:

clientId SEARCHADS....
teamId SEARCHADS....
keyId  xxxxxxxx-....
# Create your first profile
appleads auth init

appleads auth init now guides that sequence interactively. If you prefer to do it step by step:

appleads auth keygen          # generate EC P-256 keypair
appleads auth public-key      # print PEM to upload in Apple Ads UI

Then save your credentials:

appleads auth set \
  --client-id  "SEARCHADS.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
  --team-id    "SEARCHADS.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
  --key-id     "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

2️⃣ Authenticate & select org

appleads auth token           # exchange credentials for access token
appleads auth orgs --select   # pick your org interactively
appleads auth status --json   # inspect active auth/profile state

org_id is optional for token creation, but required by most campaign/report commands.

3️⃣ Verify everything works

appleads doctor               # runs 7-layer health check ✅

4️⃣ Your first commands

appleads campaigns list --limit 5
appleads orgs list --json
appleads reports campaigns --start-date 2026-04-10 --end-date 2026-04-16 --json
appleads campaigns health --json

5️⃣ Body-based commands (LLM-friendly)

Most create, update, find, and report commands accept JSON payloads:

appleads campaigns create --body-file ./payloads/campaign-create.json
appleads reports campaigns  --body-file ./payloads/report-campaigns.json

💡 Tip: Every body-based command includes copy/paste-ready examples in --help.


🗺️ Command Map

Group Commands Highlights
auth init · set · token · orgs · keygen · public-key · show/status OAuth setup, profile management
orgs list · use Top-level org discovery and switching
doctor — 7-layer health check (config → API)
campaigns list · get · create · update · delete · find · enable · pause · health Full CRUD + quick actions
adgroups list · get · create · update · delete · find · enable · pause Full CRUD + quick actions
ads list · get · create · update · delete · find · enable · pause Full CRUD + quick actions
keywords targeting · campaign-negative · adgroup-negative · recommendations Bid management & discovery
targeting show · set · clear · replace · country · device Dimension presets
reports campaigns · adgroups · keywords · searchterms · ads · impressionshare · template Presets & template generator
apps details · eligibilities · product-pages App metadata
search app · geo App & geo lookup
creatives list · get · find · create · update · delete Creative management
budget-orders list · get · create · update · find Financial controls
account me · acls Account introspection
api — Raw API caller for any endpoint
agent install-skill · link-skill · show-skill-path Install bundled Codex skill assets

Full reference: appleads --help · appleads <group> --help · appleads <group> <command> --help

Repo-local guidance also lives in AGENTS.md and skills/appleads-cli/SKILL.md.

To install the bundled Codex skill directly from the CLI:

appleads agent install-skill

For local development, if you want a symlink instead of a copied install:

appleads agent link-skill --source ./skills/appleads-cli

👥 Multi-Account Workflow

Manage unlimited profiles for different accounts, clients, or environments.

# Create profiles
appleads auth profiles create personal
appleads auth profiles create agency

# Initialize each
appleads -p personal auth init
appleads -p agency    auth init

# Switch context
appleads auth profiles use personal
appleads auth profiles switch agency   # alias
Advanced profile operations
appleads auth profiles list
appleads auth profiles rename agency agency-main
appleads auth profiles clone  agency-main agency-backup
appleads auth profiles export agency-main --out ./agency-main.profile.json
appleads auth profiles import ./agency-main.profile.json --name agency-imported

When you omit -p, appleads uses the active profile automatically.


🛡️ Safety Model

Mutations are safe by default. Every destructive or state-changing command supports:

Flag Behavior
--dry-run Preview the payload without calling the API
(default) Interactive confirmation prompt
--yes Bypass prompt — designed for CI/CD pipelines
--confirm-org <id> Abort if the resolved org does not match the expected org
# Preview what would happen
appleads targeting country add \
  --campaign-id 123456 --adgroup-id 987654 \
  --codes US,CA --dry-run

# Lock the command to one org before sending
appleads campaigns enable 123456 --confirm-org 8526150 --yes

# Execute with auto-confirm (CI mode)
appleads targeting country add \
  --campaign-id 123456 --adgroup-id 987654 \
  --codes US,CA --yes

📊 Reporting & Templates

Use first-class date flags for common report pulls:

appleads reports campaigns --start-date 2026-04-10 --end-date 2026-04-16
appleads reports searchterms --campaign-id 123456 --start-date 2026-04-10 --end-date 2026-04-16 --time-zone ORTZ

appleads reports ... now fills sane request defaults when possible:

  • selector.pagination defaults to offset=0, limit=1000
  • selector.orderBy is added automatically per report type
  • when neither granularity nor row totals are supplied, returnRowTotals=true is added

Generate report payloads in seconds with built-in presets:

appleads reports template campaigns --preset last-7d
appleads reports template keywords  --campaign-id 123456 --preset last-30d

Execute directly:

appleads reports template campaigns --preset yesterday --run

Available presets: today · yesterday · last-7d · last-30d


🩺 Health Checks (doctor)

A comprehensive 7-layer diagnostic that validates your entire setup:

✓  Config file resolved
✓  Profile loaded
✓  Auth fields present
✓  Private key readable
✓  Client secret generated
✓  Token valid / refreshed
✓  Org resolved
✓  API reachable (/me, ACLs, /campaigns)
appleads doctor              # full check
appleads doctor --no-network # skip API calls
appleads doctor --strict     # warnings → errors

Exit code is non-zero on failures. With --strict, warnings also trigger non-zero exit.


🔌 Raw API Access

Need an endpoint that doesn't have a typed command yet? Use the escape hatch:

appleads api --method GET  --path /campaigns --query limit=20 --query offset=0
appleads api --method POST --path /campaigns/find --body-file ./payloads/campaign-find.json

⚙️ Configuration

Setting Default
Config path ~/Library/Application Support/appleads/config.json
API version v5
API base URL https://api.searchads.apple.com
OAuth token URL https://appleid.apple.com/auth/oauth2/token

Global flags: --output table|json · --json · --profile <name> · --config <path> · --confirm-org <id>

# JSON output for automation pipelines
appleads campaigns list --limit 20 --json | jq '.data[].name'

🔧 Troubleshooting

Error Fix
org_id is not set Run appleads auth orgs --select or pass --org-id
401 / 403 from API Run appleads doctor then appleads auth token
404 on a command Check docs/GAP_MATRIX.md — some endpoints are capability-dependent

🤝 Contributing

  1. Fork the repo and create a feature branch

  2. Add or adjust commands

  3. Run tests:

    go test ./...
  4. Update README.md and docs/GAP_MATRIX.md when behavior changes


🔒 Security

  • Never commit real credentials or .p8 private keys
  • Use profile export/import through secured channels
  • Maintain separate profiles per client/account

📄 License

MIT


Built with ❤️ for Apple Search Ads power users

About

Production-ready CLI for Apple Search Ads API

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages