A modern, fully-typed Python client for the Apple Ads APIs with async support and Pydantic models — covering both the new Apple Ads Platform API v1 and the legacy Campaign Management API v5 (sunset January 26, 2027).
- Full Type Safety - Complete type hints with strict mypy compliance
- Async Support - Both sync and async methods in a unified client
- Pydantic Models - Validated request/response models
- Resource-based API - Intuitive
client.campaigns.list()pattern - Automatic Pagination -
iter_all()anditer_all_async()helpers - Reports with Pandas - Optional DataFrame export
Using uv (recommended):
uv add asa-api-clientUsing pip:
pip install asa-api-clientWith pandas support:
uv add "asa-api-client[pandas]"
# or
pip install "asa-api-client[pandas]"from asa_api_client import AppleSearchAdsClient
# From environment variables
client = AppleSearchAdsClient.from_env()
# Or explicit configuration
client = AppleSearchAdsClient(
client_id="SEARCHADS.xxx",
team_id="SEARCHADS.xxx",
key_id="xxx",
org_id=123456,
private_key_path="private-key.pem",
)
# List campaigns
with client:
campaigns = client.campaigns.list()
for campaign in campaigns:
print(f"{campaign.name}: {campaign.status}")Apple's new Platform API v1 replaces v5 (which stops working on 2027-01-26). The v1 client ships alongside the v5 client with the same credentials — just add your ad account ID:
from asa_api_client import AppleAdsClient
from asa_api_client.v1 import Query
client = AppleAdsClient.from_env() # reads ASA_* plus ASA_AD_ACCOUNT_ID
with client:
# Flat query-based API with typed filters
enabled = client.campaigns.query(Query().where("status", "EQUALS", "ENABLED"))
# v1-only features
recs = client.recommendations
popularity = client.insights
history = client.change_history
bulk = client.bulkDon't know your ad account ID? Run the read-only smoke check — it discovers accounts and validates the whole integration against the live API:
asa v1-smokeSee the Platform API v1 guide for the full migration crib and resource reference. Import v1 symbols from the package root (AppleAdsClient) — internal layout may change when v5 is removed.
export ASA_CLIENT_ID="SEARCHADS.your-client-id"
export ASA_TEAM_ID="SEARCHADS.your-team-id"
export ASA_KEY_ID="your-key-id"
export ASA_ORG_ID="123456"
export ASA_PRIVATE_KEY_PATH="/path/to/private-key.pem"
export ASA_AD_ACCOUNT_ID="123456" # Platform API v1 onlyOr use a .env file:
ASA_CLIENT_ID=SEARCHADS.your-client-id
ASA_TEAM_ID=SEARCHADS.your-team-id
ASA_KEY_ID=your-key-id
ASA_ORG_ID=123456
ASA_PRIVATE_KEY_PATH=private-key.pem
ASA_AD_ACCOUNT_ID=123456 # Platform API v1 only# List all campaigns
campaigns = client.campaigns.list()
# Get a specific campaign
campaign = client.campaigns.get(campaign_id)
# Find with filters
from asa_api_client.models import Selector
enabled = client.campaigns.find(
Selector().where("status", "==", "ENABLED")
)
# Create a campaign
from asa_api_client.models import CampaignCreate, Money, CampaignSupplySource
campaign = client.campaigns.create(
CampaignCreate(
name="My Campaign",
adam_id=123456789,
countries_or_regions=["US"],
daily_budget_amount=Money(amount="100", currency="USD"),
supply_sources=[CampaignSupplySource.APPSTORE_SEARCH_RESULTS],
)
)# Access ad groups through campaign
ad_groups = client.campaigns(campaign_id).ad_groups.list()
# Create an ad group
from asa_api_client.models import AdGroupCreate
ad_group = client.campaigns(campaign_id).ad_groups.create(
AdGroupCreate(
name="My Ad Group",
default_bid_amount=Money(amount="1.00", currency="USD"),
)
)# List keywords in an ad group
keywords = client.campaigns(campaign_id).ad_groups(ad_group_id).keywords.list()
# Create keywords (bulk only)
from asa_api_client.models import KeywordCreate, KeywordMatchType
result = client.campaigns(campaign_id).ad_groups(ad_group_id).keywords.create_bulk([
KeywordCreate(
text="my keyword",
match_type=KeywordMatchType.EXACT,
bid_amount=Money(amount="1.50", currency="USD"),
)
])from datetime import date
# Campaign report
report = client.reports.campaigns(
start_date=date(2024, 1, 1),
end_date=date(2024, 1, 31),
)
# Convert to DataFrame (requires pandas)
df = report.to_dataframe()import asyncio
async def main():
client = AppleSearchAdsClient.from_env()
async with client:
campaigns = await client.campaigns.list_async()
# Async iteration
async for campaign in client.campaigns.iter_all_async():
print(campaign.name)
asyncio.run(main())Generate a formatted Excel analysis workbook with the included asa analyze CLI:
pip install "asa-api-client[cli]"
asa analyze --period 90d --output report.xlsxThe workbook includes a summary sheet with KPIs and trends, formatted analysis sheets per reporting level, and raw daily data for pivoting. For details, see the CLI guide.
MIT License - Copyright (c) 2025 Peth Pty Ltd