/api/v1/candidates 标准增量调用
这页只解释标准调用流程,不会在浏览器里自动发送带 token 的请求。增量场景推荐直接用 since;服务端也兼容 updated_after。
文档分工
- 统一总入口:
docs/customer-api-overview.md。 - 这页只保留速查路径:增量怎么拉、detail 什么时候再读。
- 完整对外主文档:
docs/customer-candidate-api-consumer-guide.md。 - 稳定字段契约附录:
docs/customer-candidate-api-spec.md。 - 客户页
/customer/index.html顶部可以直接“复制 API 请求”;页面只会保留公开参数,并提示未映射的内部筛选。
如果你在给 ERP、AI 服务或内部脚本接入,请先看主文档,再回这页复制 curl 示例。
标准规则
since表示“从这个更新时间之后开始拉增量”;如果旧系统已经在用updated_after,也继续兼容。- 增量拉取固定使用
sort=updated_time_asc。 - 如果响应里还有
meta.next_cursor,继续沿用同一组筛选参数,再补cursor=<meta.next_cursor>。 - 一旦改了
platform / goods_type / search / since / engagement_primary_min这类筛选条件,就不能复用旧 cursor。 - 如果只想拿当前默认首页曝光层,额外带
visibility_scope=default_exposure;如果想看当前补充候选,用searchable_only;只看历史回看,用history_only。 - 单条详情推荐用
https://productsdev.com/api/v1/candidates/detail?candidate_id=<urlencoded candidate_id>;如果继续用路径形态/api/v1/candidates/:candidateId,必须先对完整candidate_id做 URL 编码。
标准 endpoint 形态:/api/v1/candidates?platform=facebook&since=2026-04-01T00:00:00.000Z&sort=updated_time_asc&page_size=50
标准续拉终止条件:
meta.next_cursor == null。第一次增量请求
curl -H "Authorization: Bearer $CUSTOMER_API_TOKEN" \
"https://productsdev.com/api/v1/candidates?platform=facebook&since=2026-04-01T00:00:00.000Z&sort=updated_time_asc&page_size=50"
继续下一页
curl -H "Authorization: Bearer $CUSTOMER_API_TOKEN" \
"https://productsdev.com/api/v1/candidates?platform=facebook&since=2026-04-01T00:00:00.000Z&sort=updated_time_asc&page_size=50&cursor=<meta.next_cursor>"
互动字段与筛选
- 列表默认返回
engagement和platform_metrics,不用每条先读 detail 才能拿点赞、评论、分享、评价或收藏。 - 通用区间参数:
engagement_primary_min/max、engagement_secondary_min/max、engagement_tertiary_min/max;同时传时要求min <= max。 - Facebook 分享可用
facebook_share_min/max,但必须同时带platform=facebook。 - 互动排序支持
engagement_primary_desc、engagement_secondary_desc、engagement_tertiary_desc。 0表示平台明确给出 0;null表示未知或不适用,数值阈值不会让null命中。
curl -H "Authorization: Bearer $CUSTOMER_API_TOKEN" \
"https://productsdev.com/api/v1/candidates?platform=facebook&engagement_primary_min=100&engagement_primary_max=500&engagement_secondary_min=20&sort=engagement_primary_desc&page_size=50"
Facebook 重复素材聚合
如果 ERP 列表页想先合并重复 Facebook 素材,再让操作员点进 detail 看代表卡片,可以显式带 view=creative_groups。
meta.total表示聚合后的卡片数。meta.raw_total表示同条件下未折叠前的原始候选数。- Facebook 聚合 item 可能额外带
display_group_key / display_group_count / display_group_member_ids。 - 折叠后的 Facebook grouped item 会使用组级
candidate_feedback_key和feedback_targets.candidate.path,不随代表项变化。 - 增量同步、主表落库仍建议继续使用默认
view=raw;如果列表展示用了 grouped item,feedback 写回必须直接复用 item 自带的feedback_targets。
curl -H "Authorization: Bearer $CUSTOMER_API_TOKEN" \
"https://productsdev.com/api/v1/candidates?platform=facebook&view=creative_groups&page=1&page_size=50"
列表返回字段(/api/v1/candidates)
meta.next_cursor:下一页游标;为空表示当前窗口已经拉完。meta.has_more:是否还有后续页。meta.raw_total:只在view=creative_groups时返回;表示同条件下原始候选总数。filters.updated_time_start:服务端实际采用的增量起点。items[*].updated_time:用于 ERP 持久化同步位点。items[*].candidate_feedback_key:当前素材卡片的 feedback 资源键;写 candidate feedback 时优先使用feedback_targets.candidate.path,不要用裸candidate_id自己拼。items[*].keyword_feedback_key:如果后续要写 keyword feedback,直接把这个值当成/api/v1/feedback/keywords/:platform/:entityKey的:entityKey;不要自己按source_keyword重算。items[*].keyword_feedback_key_source:说明 key 来源;source_keyword表示 API 可由来源词稳定生成,workspace_key表示沿用客户工作台已存在的资源键。items[*].feedback_targets:反馈写回导航;candidate是当前素材卡片,keyword是平台来源词,suggestion是平台级建议。ERP 优先使用里面的path,不要自己猜路由。items[*].feedback_state_scope:candidate表示单条素材卡片;facebook_creative_group表示 Facebook 折叠分组卡片。items[*].engagement:统一互动事实对象,包含primary / secondary / tertiary三层语义和has_structured / has_comparable。items[*].platform_metrics:平台原始互动数;Facebook 是 reaction/comment/share,TikTok 是 like/comment,Etsy 是 review/favorite。items[*].display_group_*:只在view=creative_groups的 Facebook item 上出现,表示这张代表卡片折叠了哪些重复素材。items[*].start_date / content_time:第一阶段返回同值,便于外部系统平滑迁移。- Facebook 固定取
startDate作为这两个字段的输出来源,不会把contentDateIso单独暴露成另一套内容时间。 - Etsy 当前会额外补读同一轮 snapshot projection,所以
searchable_only / history_only可能比原始workspace.json文件里看到的更多,但仍只限当前发布快照。 - 如果还会读取
workspace.json.latest.etsy的 fresh lane 报数,要区分captureFreshLaneEligibleCount(可检索 fresh 总量)、captureFreshLaneRelevantEligibleCount(真正可占默认曝光位的子集)和captureFreshLaneSelectedCount(最终挂出的 fresh 数)。 - 判断 Etsy fresh lane 是否配额不足或挂出偏少时,优先看
captureFreshLaneRelevantEligibleCount,不要直接把captureFreshLaneEligibleCount当成“应该挂出的数”。
总量解释字段(/api/v1/meta)
candidate_count:当前快照总候选数,包含default_exposure + searchable_only + history_only。searchable_candidate_count:当前可检索候选数,只包含default_exposure + searchable_only。platform_visibility_counts:每个平台分别有多少default_exposure / searchable_only / history_only,用来直接解释总量来自哪里。- 如果当前 snapshot 只有顶层 visibility 聚合、但没有足够的平台级归因信息,
platform_visibility_counts会返回null,避免输出自相矛盾的拆分结果。
什么时候再读 detail
列表只负责增量发现;如果要做 AI 深度分析,再按候选 ID 读取 detail。Facebook 的 candidate_id 常含完整 URL 和 ?,不要把原值直接拼进路径。推荐使用 https://productsdev.com/api/v1/candidates/detail?candidate_id=<urlencoded candidate_id>。如果只是要写 keyword feedback,不需要先读 detail,直接复用列表里的 keyword_feedback_key 即可。
curl -H "Authorization: Bearer $CUSTOMER_API_TOKEN" \
"https://productsdev.com/api/v1/candidates/detail?candidate_id=<urlencoded candidate_id>&include=raw_html"