简介:本文系统梳理程序化广告投放接口的对接全流程,从授权鉴权、账户定位到各层级资源创建。针对多版本接口混用、请求头命名不一致、媒体类型(MIME)校验严格、部分成功响应处理等高频陷阱逐一剖析,并提供可直接对照调试的请求与响应示例,帮助后端开发者少走弯路、快速完成稳定对接。
做过程序化广告对接的后端同学大多有过类似体验:官方文档看起来章节齐全,真正动手联调时却处处卡壳。问题的根源通常集中在三个方面。
第一,接口并非单一版本体系。 广告活动(Campaign)的创建属于广告平台的一类管理接口,其路径带有明显的版本化特征;而广告组(AdGroup)及其下级资源(关键词、商品定向、否定词等)则走另一套资源型接口。两套接口在请求头、媒体类型、响应结构上完全不通用,混用会直接触发鉴权失败或格式错误。
第二,请求头存在两套命名规范。 一类接口使用客户端 ID 与账户 ID 组合的头部字段,另一类接口则使用客户端 ID 与作用域(Scope)组合的头部字段。字段名相似但语义不同,复制粘贴时极易混淆,一旦混用便返回 403。
第三,媒体类型不能统一写成通用 JSON。 资源型接口的每个子资源都要求专属的 vendor MIME 类型,例如关键词资源对应 application/vnd.spKeyword.v3+json 这类带版本标识的格式。写成 application/json 会得到 415,写成错误版本号则得到 400。
理解这三点之后,整体创建链路就清晰了。下面按实际对接顺序展开。
授权(OAuth) --> 账户档案(Profiles) --> [组合(Portfolio) 可选]--> 广告活动(Campaign)--> 广告组(AdGroup)--> 商品广告(ProductAds)--> 关键词(Keywords)--> 商品定向(Targets)--> 否定关键词(NegativeKeywords)--> 否定定向(NegativeTargets)--> 活动级否定关键词(CampaignNegativeKeywords)--> 活动级否定定向(CampaignNegativeTargets)
广告活动是顶层容器,广告组必须挂在活动下,而商品广告、关键词、定向等资源又必须挂在广告组下。任何一层缺失都会导致后续创建返回无效父级引用。组合(Portfolio)是可选的财务归类容器,不影响创建链路主干。
所有投放接口请求都需要携带 Bearer 访问令牌。标准流程采用 OAuth 2.0 授权码模式:
client_id、scope(广告活动管理类作用域)、response_type=code、redirect_uri 等参数;Authorization: Bearer <access_token>。令牌有效期有限,需实现刷新逻辑;刷新令牌本身也有较长周期,应持久化存储并做好失效告警。注意不同区域(北美、欧洲、远东)的授权端点与接口域名不同,区域路由错误会表现为令牌无效或资源不存在。
拿到令牌后,第一步不是直接创建活动,而是查询当前授权账号可操作的账户档案列表。接口返回的档案对象包含档案 ID、所属区域、账户类型、货币等信息。后续所有资源型请求的 Scope 头部值,填写的就是这个档案 ID,而不是卖家账户 ID 或广告账户 ID。这是新手最常见的错误之一:把账户 ID 填进 Scope,结果所有请求 403。
建议在系统中缓存“授权账号 → 档案 ID 列表”的映射,并在令牌刷新后校验档案是否仍然有效。
投放接口按区域划分域名,北美、欧洲、亚太各自独立。档案对象中会标明所属区域,创建资源时应根据档案区域选择对应域名,避免跨区调用。
活动创建走版本化管理接口,请求体核心字段包括:
name:活动名称,需在账户内唯一性上做业务校验;budget:预算对象,含金额与预算类型(日预算/生命周期预算);startDate / endDate:起止日期;portfolioId:可选,关联组合;state:初始状态,建议先创建为暂停(paused),配置完成后再启用,避免空活动消耗预算。请求头使用“客户端 ID + 账户 ID”组合,媒体类型为通用 JSON。响应中返回活动 ID,该 ID 是后续广告组创建的必要参数。
实践建议:活动创建成功后立即落库并记录外部 ID 与本地业务主键的映射,便于幂等重试与对账。
广告组走资源型接口,请求头切换为“客户端 ID + Scope(档案 ID)”组合,媒体类型使用广告组专属 vendor MIME。请求体关键字段:
{"name": "adgroup-demo-01","campaignId": "1234567890","defaultBid": 0.75,"state": "paused"}
defaultBid 是广告组默认竞价,单位为货币最小单位(通常为分),需与账户货币一致。campaignId 必须来自上一步真实返回,不可伪造。
响应结构通常是数组包裹的资源列表,并带有 code 与 details 字段标识成功或失败。注意:这类接口普遍支持“部分成功”语义——批量提交多个资源时,整体 HTTP 状态可能是 207,响应体中逐个资源标注成功或失败原因。必须遍历响应数组判断每个元素,而不能只看顶层状态码。
商品广告把具体商品(ASIN 或 SKU)挂到广告组下。请求体需提供 adGroupId、商品标识(ASIN 列表或 SKU 列表)、state。媒体类型为该资源专属 MIME。
这里有一个容易忽略的前置问题:推广商品从哪里来? 实践中通常有两种来源:一是通过商品目录类接口按 ASIN 查询商品基础信息与可售状态;二是从卖家自有商品库同步。无论哪种,都建议在创建广告前校验商品是否可售、是否属于当前账户,否则创建会失败或广告无法投放。
关键词是搜索型投放的核心。请求体字段包括:
{"adGroupId": "9876543210","keywordText": "wireless charger","matchType": "PHRASE","bid": 0.85,"state": "enabled"}
matchType 取值包括广泛匹配、词组匹配、精确匹配。bid 为该关键词竞价,需与广告组默认竞价策略配合:若使用“下调竞价”策略,实际竞价可能低于设定值。
关于关键词的来源:程序化创建时,关键词通常来自业务侧的关键词库、搜索词报告或第三方选词工具的结果导入。接口本身不提供“推荐关键词”能力,选词逻辑需在业务层完成。创建前应做去重与长度、字符集校验,避免批量提交后大量部分失败。
商品定向用于按品类、品牌、价格区间等维度定向。请求体结构依定向类型而变,常见字段包括 expression(定向表达式,如品类 ID 列表)、bid、state。
这里有一个必须提前知道的限制:自动投放类型的定向目标(由系统自动匹配的投放组)通常不允许通过创建接口直接新建,只能通过列表接口查询或通过更新接口调整。如果业务代码里对自动投放也调用创建接口,会持续收到校验错误。正确做法是:自动投放的定向在广告组创建后由系统生成,开发者只做查询与更新(如调整竞价、启停),而不是创建。
否定资源用于排除不相关流量,分为广告组级与活动级两层:
adGroupId + keywordText + matchType(否定匹配通常只支持词组与精确);adGroupId + expression;campaignId + keywordText;campaignId + expression。否定资源的媒体类型同样是各自专属 MIME,不可复用正向关键词的 MIME。否定品牌这类定向也通过否定定向接口表达,表达式中使用品牌维度字段。
创建顺序上,建议先建正向资源再建否定资源,因为否定逻辑依赖对投放结构的完整理解;但接口层面两者并无强依赖。
| 陷阱 | 表现 | 应对 |
|---|---|---|
| 两套 Header 混用 | 403 | 按接口版本区分头部字段,封装统一客户端屏蔽差异 |
| Content-Type 写通用 JSON | 415 或 400 | 每个资源维护专属 vendor MIME 常量 |
| 忽略 207 部分成功 | 数据不一致 | 逐元素解析响应,失败项单独重试 |
| Scope 填账户 ID | 403 | Scope 必须是档案 ID |
| 自动投放调创建接口 | 校验失败 | 自动投放只查询与更新,不创建 |
| 竞价单位错误 | 竞价异常 | 确认货币最小单位,统一做单位换算 |
| 跨区域调用 | 资源不存在 | 按档案区域路由域名 |
这类投放接口的复杂度主要不在业务逻辑,而在“多版本、多头部、多 MIME、部分成功”这些工程细节上。把授权与档案定位做扎实,把两套接口的差异封装干净,把 207 响应解析到位,后续的创建链路就会顺畅很多。希望本文的梳理能让正在对接投放接口的后端同学少踩几个坑。