营销增长
需要用 asc 管理 Apple Ads 的认证…
适用于通过 asc CLI 管理 Apple Ads 广告账户、Platform API v1 与旧 v5、报表、素材、推荐、受限变更和迁移的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
需要用 asc 管理 Apple Ads特定
解决思路
- 通过 `asc ads` 执行 Apple Ads 工作;把 Apple Ads 凭证与 App Store Connect 凭证分开配置,注意 `asc auth login` 不会配置 Ads。
- 选择 API:直接运行 `asc ads <resource> ...` 使用 Apple Ads Platform API v1,并需要 ad account ID。
- 已弃用的 Campaign Management API v5 命令位于 `asc ads v5 ...`,使用 organization ID;Apple 于 2027-01-26 停止支持 v5。
- 不要把 org ID 当作 ad account ID;CLI 将二者分开。
- 在构造请求文件前,对确切叶子命令运行 `--help`;v1 的 payload 和响应 envelope 与 v5 不同,CLI 不做转换。
- 非交互式管道中传 `--file -` 从 stdin 读取 JSON 请求体;当 stdin 是终端时 CLI 会拒绝。
- Resource、report、upload、raw 命令输出无损 JSON;用 `jq` 做投影,不要请求 table 或 markdown 输出。
- 当 profile 需同时支持 v1 和旧 v5 时,存储两种上下文:`asc ads auth login --name 'Marketing' --client-id '$ASC_ADS_CLIENT_ID' --team-id '$ASC_ADS_TEAM_ID' --key-id '$ASC_ADS_KEY_ID' --private-key '$ASC_ADS_PRIVATE_KEY_PATH' --ad-account '987654' --org '123456' --network`。
- CI 中设置 Ads 专用变量并绕过 host keychain:`export ASC_ADS_CLIENT_ID='SEARCHADS_CLIENT_ID'`、`export ASC_ADS_TEAM_ID='SEARCHADS_TEAM_ID'`、`export ASC_ADS_KEY_ID='KEY_ID'`、`export ASC_ADS_PRIVATE_KEY_PATH='$HOME/.asc/apple-ads-private-key.pem'`、`export ASC_ADS_AD_ACCOUNT_ID='987654'`、`export ASC_ADS_BYPASS_KEYCHAIN=1`。
- `ASC_ADS_PRIVATE_KEY` 和 `ASC_ADS_PRIVATE_KEY_B64` 也可用;如果另一个受信进程签发了短期 token,设置 `ASC_ADS_ACCESS_TOKEN`;有 scope 的 v1 调用仍需要 ad account ID。
- 检查认证而不打印 token:`asc ads auth status --validate --output json`;`asc ads auth discover --ads-profile 'Marketing' --output json`;`asc ads auth doctor --output json`。
- Discovery 调用 Platform v1 `GET /v1/me` 和 `GET /v1/acls`;比较每个 ACL 的 ad-account ID、name、organization ID 和 roles,绝不自动选择第一个结果;在任何 mutation 前打印所选账号;当有多个 profile 或账号时同时传 `--ads-profile 'Marketing'` 和 `--ad-account '987654'`。
- 对命名 profile,profile 的 `ad_account_id` 和 `org_id` 独立存在,不继承另一个 profile 或 root config 的上下文;v1 上下文优先级为 `--ad-account`、`ASC_ADS_AD_ACCOUNT_ID`、所选 profile、无 profile 的 root config;legacy v5 使用对应的 `--org` 与 `ASC_ADS_ORG_ID` 链。
- 身份和 ACL 调用不需要 ad account 上下文:`asc ads me view --ads-profile 'Marketing' --output json`;`asc ads acls list --ads-profile 'Marketing' --output json`;`asc ads orgs view --ads-profile 'Marketing' --org-id '123456' --output json`。
- 用小型 app search 证明所选账号:`asc ads apps search --ads-profile 'Marketing' --ad-account '987654' --query 'Example' --limit 1 --output json`。
- App search 至少需要 `--query`、`--cpids`、`--return-owned-apps` 之一;Storefront 使用逗号分隔的 ISO alpha-2 代码;仅在需要每个搜索结果时添加 `--paginate`。
- 用各资源的 `find` 命令盘点;多数 v1 查询把 filters、sorting 和 pagination 放在 JSON 对象中;从属资源过滤示例:`filters` 数组包含 `field` 为 `campaignId`、`operator` 为 `EQUALS`、`value` 为 `[campaign-id]`,`pagination` 为 `offset=0, pageSize=100, fetchTotalCount=true`。
- 运行 `asc ads campaigns find --ads-profile 'Marketing' --ad-account '987654' --output json`;`asc ads ad-groups find --ads-profile 'Marketing' --ad-account '987654' --file query.json --output json`;`asc ads ads find --ads-profile 'Marketing' --ad-account '987654' --file query.json --output json`。
- `campaigns find` 省略 `--file` 会请求默认第一页;要控制或取尽结果集,在查询文件中使用 `pagination.offset`、`pageSize`、`fetchTotalCount`,读取响应 pagination 并递增 offset 直到完整;该命令没有 `--paginate` flag。
- Platform filters 使用单数 `value`;不要复制 v5 `Selector` 字段如 `conditions` 或复数 `values`,当前 `asc` 在认证前就会拒绝。
- 直接 v1 树还覆盖 ad accounts 和 advertiser resources;app eligibility、locales、product pages、rejection reasons;brands、business categories、locations、location groups、creatives、assets;geographic targeting 和 shared budgets;apps 与 brands 的 reports;insights、suggestions、recommendations、change history;用 `asc ads change-history --help`、`asc ads suggestions --help`、`asc ads rejection-reasons --help`、`asc ads reports brands --help` 发现确切叶子,不要回退到 raw HTTP。
- Keyword 查询需要 selector 文件;targeting keywords 需要 `id`、`adGroupId` 或 `campaignId` filter;negative keywords 需要 `id` 或 `adGroupId`;campaign-level negative keywords 组合 `campaignId` 与 operator 为 `IS_NULL` 的 `adGroupId` filter。
- 运行 `asc ads targeting-keywords find --ads-profile 'Marketing' --ad-account '987654' --file keyword-query.json --output json`;`asc ads negative-keywords find --ads-profile 'Marketing' --ad-account '987654' --file negative-keyword-query.json --output json`。
- V1 reports 需要 endpoint-specific body;日期在 `timeRange` 下,分页用 `offset` 和 `pageSize`,campaign 或 ad-group ID 放在 `filters` 中;示例:`pagination.offset=0`、`pagination.pageSize=20`、`filters` 中 `field=campaignId, operator=EQUALS, value=[campaign-id]`、`groupBy=[countryOrRegion]`、`timeRange.start=2026-08-01`、`timeRange.end=2026-08-14`、`timeRange.timeZone=ORTZ`、`timeRange.granularity=DAILY`。
- 运行 `asc ads reports apps campaigns --ads-profile 'Marketing' --ad-account '987654' --file report.json --output json`。
- Report 命令不接受 `--paginate`;在 body 中改分页;检查叶子 help,因为 report entities 接受不同 `groupBy` 和 option values。
- Recommendations 和 suggestions 也使用 endpoint-specific bodies;apply 或 dismiss recommendations 可能改变花费并需要 `--confirm`:`asc ads recommendations daily-budgets find --ads-profile 'Marketing' --ad-account '987654' --file query.json`;`asc ads recommendations daily-budgets apply --ads-profile 'Marketing' --ad-account '987654' --file recommendations.json --confirm`。
- 在用户批准 ad account、resource type、target IDs 和已审查 payload 前不要 mutate;把请求 JSON 保存在文件中;绝不要从相关 v5 schema 编造字段。
- Campaign 创建可能开始花费;`CampaignCreate` 需要 `adAccountId`、`billingEvent`、`dailyBudget`、`name`、`promotedObjectId`、`promotedObjectType`、`targeting`;CLI 原样发送文件,`--ad-account` 只选择请求上下文,不会把 `adAccountId` 注入 JSON;从 paused 形状开始,把每个 placeholder 替换为从所选账号读取的值,并按当前 Apple v1 schema 复查账户特定要求。
- Campaign 创建 payload 的 paused 形状示例字段:`name` 为 `ASC agent validation 2026-08-15T00:00:00Z`、`status` 为 `PAUSED`、`adAccountId` 为 987654、`promotedObjectType` 为 `APPSTORE_APP`、`promotedObjectId` 为 `123456789`、`billingEvent` 为 `TAPS`、`dailyBudget.value.amount` 为 `1`、`dailyBudget.value.currency` 为 `USD`、`startTime` 为 `2030-01-01T00:00:00.000`、`endTime` 为 `2030-01-02T00:00:00.000`、`targeting.countryOrRegion.include` 为 `[US]`、`bidStrategy.bidStrategyType` 为 `MANUAL_CPT`、`bidStrategy.bidStrategyGoal` 为 `TAP`。
- 顶层显式 `status` 为 `PAUSED` 的 payload 可不加 `--confirm` 运行;省略 status 或非 paused status 需要 `--confirm`。运行 `asc ads campaigns create --ads-profile 'Marketing' --ad-account '987654' --file paused-campaign.json`;`asc ads campaigns pause --ads-profile 'Marketing' --ad-account '987654' --campaign 'campaign-id'`;`asc ads campaigns resume --ads-profile 'Marketing' --ad-account '987654' --campaign 'campaign-id' --confirm`。
- Campaign 更新在可能改变 budget、targeting、bids、delivery、dates 或 status 时需要 `--confirm`;仅改 name 或 name 加 `PAUSED` status 不需要;deletes、bulk creates/updates、recommendation apply/dismiss、budget-order writes 和其他高风险 mutation 在 auth 或 network access 前需要确认。
- Ad-group 创建和 keyword bulk writes 是总是需要确认的 delivery/targeting 变更;v1 bulk keyword 文件使用 wrapper objects 如 `KeywordCreateBulkRequest`,不是 v5 raw-array 形状。运行 `asc ads ad-groups create --ads-profile 'Marketing' --ad-account '987654' --file ad-group.json --confirm`;`asc ads targeting-keywords create-bulk --ads-profile 'Marketing' --ad-account '987654' --file keywords.json --confirm`;`asc ads targeting-keywords delete --ads-profile 'Marketing' --ad-account '987654' --keyword 'keyword-id' --confirm`。
- Shared budgets 使用 `budget-orders` command group;create、update、delete 无上下文但需要确认;view 和 find 接受可选 ad-account 上下文。命令:`asc ads budget-orders create --ads-profile 'Marketing' --file shared-budget.json --confirm`;`asc ads budget-orders update --ads-profile 'Marketing' --budget-order 'budget-id' --file update.json --confirm`;`asc ads budget-orders delete --ads-profile 'Marketing' --budget-order 'budget-id' --confirm`。
- Ad-account 创建也需要 `--confirm`,因为其 account family 不能更改且 Apple 无 delete endpoint;包含 `delegations` 的 ad-account update 需要确认,因为它会替换完整列表。
- Brand assets 使用专用 multipart 命令;轮询直到 Apple 处理完成:`asc ads assets upload --ads-profile 'Marketing' --file ./brand.png --brand 'BRAND_ID' --ad-account '987654'`;`asc ads assets view --ads-profile 'Marketing' --asset 'ASSET_UUID' --ad-account '987654'`。
- 仅当 `eligibility.status` 为 `ELIGIBLE` 时使用 asset;对 `LIMITED` 检查 `allowedGroups`;不要附加 `PENDING` 或 `INELIGIBLE` asset。
- 常规工作使用 first-class commands;raw v1 请求仅接受 `v1/...` 路径或 `https://api.ads.apple.com/v1/...` URL:`asc ads api request --method POST --path v1/campaigns/query --ads-profile 'Marketing' --ad-account '987654' --file query.json --output json`。
- Unknown mutations fail closed,已知高风险 mutation 需要 `--confirm`;raw 命令拒绝 multipart asset upload,改用 `asc ads assets upload`。
- 保持 legacy 调用显式:`asc ads v5 api request --method POST --path v5/campaigns/find --ads-profile 'Marketing' --org '123456' --file selector.json --output json`。
- 逐命令迁移 v5:把现有 v5 payload 保留在 `asc ads v5` 下,直到每个脚本都有审查过的 v1 body 和 response parser。
- 常见迁移映射:`asc ads v5 campaigns list` 到 `asc ads campaigns find`;`asc ads v5 apps localized-details` 到 `asc ads apps locales find`;`asc ads v5 product-pages list` 到 `asc ads product-pages find`;`asc ads v5 reports campaigns` 到 `asc ads reports apps campaigns`;`asc ads v5 campaigns pause` 或 `resume` 到 `asc ads campaigns pause` 或 `resume`;v5 campaign 或 ad-group negative keywords 到在 body 中带 scope 的 `asc ads negative-keywords ...`。
- 有七个 v5 叶子没有单命令 v1 替代:product-page countries、product-page devices、targeting-keyword bulk delete、两个 negative-keyword bulk delete、impression-share report list 和 view;不要假装 `geo search`、`insights impression-share` 或 single-resource deletes 保持这些契约。
- 从 ACL discovery 和 one-result app search 开始。
- 可丢弃 campaign 测试使用唯一带时间戳的 name 和显式 `PAUSED` status。
- 从 JSON 输出保存每个创建的 ID。
- 在检查其他内容前暂停 spend-bearing resources。
- 用 `asc ads campaigns view --ads-profile 'Marketing' --ad-account '987654' --campaign 'campaign-id' --output json` 重读测试 campaign。
- 仅删除测试创建的 campaigns:`asc ads campaigns delete --ads-profile 'Marketing' --ad-account '987654' --campaign 'campaign-id' --confirm`;不要删除预先存在的 parent。
- 再次运行相同 `campaigns view`;把 Apple 的 not-found 响应视为 cleanup proof;报告任何仍存在或无法移除的 campaign。
适用边界 · 注意事项
- 没有安装 asc CLI、没有 Apple Ads API 凭证或没有广告账户访问权限时不要使用。
- 仅做 App Store Connect 操作、不涉及 Apple Ads 时不要使用;asc auth login 不会配置 Ads。
- 需要处理没有单命令 v1 替代的 v5 边缘接口时不要假装迁移完成,应保留 v5 或单独实现。