马 马克数据 · 采集对接 API 文档
本页无需登录,可直接把链接发给采集合作方

API文档(采集对接 · SaaS 多租户版)

本页面向采集合作方:只包含 4 类数据的拉取与回推接口。系统已升级为多用户 SaaS,数据按用户隔离。

对接须知

鉴权:所有采集接口统一用请求头 X-Api-Key: <采集密钥>(也兼容 ?api_key= 参数)。 密钥由运营方发放,请勿写入前端代码或公开仓库。
返回格式:所有接口返回 {code, msg, data},code=0 表示成功。 401=密钥缺失或失效,403=无权限(用户被禁 / 授权无效 / IP 被封 / 该密钥未授权此平台),429=触发频率限制。
任务归属:平台级密钥(scope=platform)可一次领取全部用户的任务,返回行带 user_id 与 shop_id, 回传时按店铺 / 链接自动归属到对应用户,一般无需关心 user_id;
任务可能少于"待采总数":同一件商品 / 同一个店铺 / 同一个关键词被多个用户同时追踪时, 系统只会下发一条任务(跨用户去重),采集结果由系统自动分发给他们。 计费口径:只向"需要采集数据"的用户计费 —— 对方本轮也在自己的采集周期内则照常扣费, 不在采集周期内则数据照给、免费共享。这是预期行为,不是漏发。
批次号:claim=1 时系统生成批次号并返回(详情 B / 评论 R / 关键词 K 前缀), 回传时带上 collect_batch 便于对账。
平台权限(按密钥配置):一个密钥可以被限定为只能采某几个平台(如只会采虾皮、只会采亚马逊, 由运营方在后台勾选)。
  · 拉取:只返回该密钥被授权平台的任务,返回体里的 platforms 字段就是你的平台范围 ("all" 表示不限);可用 platform=shopee 进一步只拉某一个平台 (多平台采集机可以分流,互不抢其它平台的任务)。
  · 回推:非授权平台的数据会被 403 拒绝,且不入库、不扣费。 这种拒绝是"用错密钥",不要自动重试,请改用对应平台的密钥或联系运营方调整权限。
  · 每个平台各有一条独立的任务批次,互不影响 —— 虾皮采集方与亚马逊采集方可以同时跑同一个用户的任务。

接口一览(4 类数据 · 拉取 + 回推)

数据类型拉取任务(GET)回推结果(POST)
链接详情 api/collect.php?action=list&type=detail&claim=1 api/callback.php
评论 api/collect.php?action=list&type=review&claim=1 api/review_callback.php
店铺 api/shop_collect.php?action=list api/shop_callback.php
关键词 api/keyword_collect.php?action=list&claim=1 api/keyword_callback.php
调用顺序:先 拉取 拿到任务(带 link_id / keyword_id 等定位标识),采集完成后按同一批标识 回推; 回推接口统一使用 Content-Type: application/json。下面按数据类型逐组说明。

1链接详情 拉取任务 → 回推采集结果

GET api/collect.php?action=list&scope=need&claim=1&type=detail&limit=50

功能

获取当前密钥用户的待采集商品链接。按用户隔离;仅返回已标记待采集或采集频率已到期、且开关开启、且不在失败冷却窗口内的链接;用户积分不足 / 授权失效时返回空列表(msg 里会写明 reason)。type=detail 详情采集 / type=review 评论采集,两类独立维护批次与状态。claim=1 自动生成批次号。
「失败冷却窗口」= 上一次回推被判为采集失败后,系统给它安排的静候期(默认 30 分钟,可在后台调整),到期后自动重新排入任务。

请求头

X-Api-Key: ckxxxxxxxx

请求参数

参数必填说明
action是list=拉取待采集;history=历史批次(传 link_id)
type否detail(默认)=详情,review=评论
scope否need(默认)=已标记待采集 或 采集频率到期(且不在失败冷却中);marked=仅标记待采集;all=全部(诊断用,不做跨用户去重过滤)
claim否1=领取并生成批次号(详情B前缀/评论R前缀)
limit否默认50,最大500
batch否指定批次号继续拉取未完成部分
mode否push=只领取「主动触发」的任务(仅限后台配成主动触发的平台),返回行会带 trigger;不传=只领取普通拉取的任务
user_id否平台级密钥下可选,只领取指定用户的任务

返回要点

link_id / user_id / shop_id / product_link / product_id / site_name / collect_batch / pending_total;用户密钥模式下额外回带 credit / license_active,便于采集端提示"积分不足 / 授权到期"。
店铺相关字段(2026-09-29 新增,采集方按店铺抓整店链接用):
字段说明
shop_username店铺账号名(= 店铺名,如 mrsexshop)。用它打开店铺主页就能把该店所有外显链接一次抓回来
username_knowntrue=店铺名已有值可直接用;false=还没采集到,此时请用 shop_url(数字ID版店铺主页)
shop_url店铺主页链接 https://shopee.tw/shop/<platform_shop_id>,不依赖店铺名,永远可用
shop_avatar_url店铺头像
shop_name / shop_display_name备注名 / 平台真实店名(展示用,不适合当标识)
POST api/callback.php

功能

回推商品详情采集结果(1.json 格式 payload),解析入库并按单价扣减用户积分,写入流水 collect_detail。 若该商品正被其他用户追踪,系统会把本次结果自动分发给他们:对方本轮也在自己的采集周期内 → 照常计费; 不在采集周期内 → 数据照给但不计费(免费共享)。响应里的 shared_users 是共享到的总人数, shared_free_users 是其中免费共享的人数,采集方不需要做任何额外动作。

回推准入规则(重要)

系统在入库前会先判两道,命中即不入库、不扣费,但仍然返回 code:0 (收到但不采纳,请勿重试)。用 accepted 与 skip_reason 区分:
· skip_reason=collect_failed:payload 里自报 status=error/ error_msg,或根本解析不到商品ID与标题 → 判为采集失败。系统会把该链接标成 「采集失败」并进入冷却窗口(默认 30 分钟,之后自动重试),这轮不写任何详情、不扣费。
· skip_reason=duplicate_retry:同一条链接的同一个 collect_batch 已经成功回推过, 或者没带批次号而该链接本轮已完成且未到采集周期 → 判为重复推送。
采集失败时请照实回推错误(不要回推空壳/占位数据):系统会记失败状态并安排稍后重试, 比推一条空数据更有利于把问题暴露出来。

请求头

X-Api-Key: ckxxxxxxxx Content-Type: application/json

请求体参数

参数必填说明
payload是1.json 结构原始数据(item / product_review / shop_detailed / description_info)
link_id否链接id,缺省按 product_id 自动匹配(仅匹配当前用户的链接)
shop_id / product_id / product_link否辅助匹配字段
user_id否平台级密钥下可选,同一商品被多用户追踪时用于指定归属
collect_batch否详情批次号,用于推进批次进度并作为判重凭据(强烈建议带上)

返回要点

accepted(true=已采纳入库;false=已收到但未采纳)/ skip_reason / reason(未采纳的具体原因)/ detail_id / shared_users(共享到的总人数)/ shared_free_users(其中免费共享人数)/ credit_deducted(本次扣费,未采纳时为 0)/ credit_balance(扣减后余额)

2评论 拉取任务 → 回推采集结果

GET api/collect.php?action=list&scope=need&claim=1&type=review&limit=50

功能

拉取待采集评论的商品链接。与详情拉取是同一个接口,只是把 type 换成 review: 评论有独立的开关、频率、批次(R 前缀)与完成状态,因此同一件商品可能"详情已采、评论还没采"。

请求头

X-Api-Key: ckxxxxxxxx

请求参数

参数与「链接详情拉取」完全一致,仅 type=review;返回行额外带评论相关状态,定位用 link_id / product_id / shop_id。
POST api/review_callback.php

功能

回推评论采集结果(reviews 数组),逐条入库并按单价扣减用户积分(一轮扣一次,不按条数),写入流水 collect_review。 同样支持跨用户分发(响应 shared_users / shared_free_users)。

回推准入规则(重要,与商品详情同一套口径)

入库前先判两道,命中即不入库、不扣费,但仍返回 code:0:
· skip_reason=collect_failed:payload 自报 error/timeout,或这轮评论里 没有一条是有效内容(没内容、没昵称、没星级全被过滤)→ 判为采集失败, 标「评论采集失败」并进入冷却窗口(默认 30 分钟)。空壳评论不会写进库。
· skip_reason=duplicate_retry:该链接的同一个 collect_batch 已经回推过评论 (或没带批次号而本轮评论已完成且未到采集周期)→ 判为重复推送。
建议一定带上 collect_batch:它是判重的凭据;不带就只能靠"本轮是否已完成"来兜底。

请求头

X-Api-Key: ckxxxxxxxx Content-Type: application/json

请求体参数

参数必填说明
reviews是评论数组(reviewer_name / rating_star / review_content / review_sku / review_time)
link_id否链接id,缺省按 product_id + shop_id 匹配(仅当前用户)
user_id否平台级密钥下可选,指定归属用户
collect_batch否评论批次号(R前缀)并作为判重凭据(强烈建议带上)

返回要点

accepted / skip_reason / reason / review_inserted(实际入库条数)/ shared_users / shared_free_users / credit_deducted / credit_balance

3店铺 拉取任务 → 回推采集结果

GET api/shop_collect.php?action=list&limit=50

功能

拉取需要采集店铺用户名的店铺(与详情批次联动)。同一个平台店铺被多用户追踪时只下发一条任务。
店铺名字段说明(重要):username 就是店铺账号名(如 mrsexshop), 采集方拿到它就能打开 https://shopee.tw/{username} 把这家店的所有外显链接一次抓回来。
详情采集任务(collect.php)的每一行也已带 shop_username / username_known / shop_url, 一般不需要再单独调本接口查店名。

请求头

X-Api-Key: ckxxxxxxxx

请求参数

参数必填说明
action否list(默认)拉取"待采集用户名"的任务;
shops 只读查询店铺清单(不计费、不改状态、不限批次是否在跑)
batch否指定详情批次号;不传则自动取进行中的详情批次
limit否默认50,最大500
user_id否平台级密钥下可选,只拉取指定用户的店铺
link_id否仅 action=shops:按商品链接ID反查它所属的店铺(最常用的用法)
shop_id否仅 action=shops:按平台店铺ID单店查询
keyword否仅 action=shops:按备注店名 / 平台店名 / 店铺账号名 模糊搜索

返回字段(list 与 shops 一致)

字段说明
user_id店铺归属用户
shop_id平台店铺ID
username店铺账号名(= 店铺名)。为空表示还没采集到
username_knowntrue=我方已有该店的用户名,可直接用;false=需要先采集
shop_display_name平台真实店名(营销长名,仅展示用,不适合当标识)
shop_name该用户自己起的备注名(如「矮胖」),仅展示用
shop_link / shop_url店铺主页链接,只用平台店铺ID拼接 → 即使 username 还没采到也一定可用
avatar_url / site_name / platform_name / collect_batch头像 / 站点 / 平台 / 关联的详情批次号
readonly / charged(仅 shops)readonly=true、charged=0:明确这是查询,不产生任何积分
list 口径(2026-09-29 放宽):返回「批次命中且未回传」∪「username 仍为空」的店铺。 后者是兜底 —— 批次已关单但店铺行还挂着旧批次号、曾回传过空用户名却被标成已采集、 或后加的从没进过批次的店,只要还没有店铺名就一定会被下发,不会再出现"永远拿不到店铺名"。
注意:店铺名已经采到手的店不会被重新塞回 list(避免重复扣用户的店铺采集费)。 要拿已采到手的店铺名,请用 action=shops(只读、免费、随时可查)。
POST api/shop_callback.php

功能

回推店铺用户名并按单价扣减用户积分(流水 collect_shop)。回推后系统自动共享给同轮追踪该店铺的其他用户(响应 shared_users)。

请求头

X-Api-Key: ckxxxxxxxx Content-Type: application/json

请求体参数

参数必填说明
shop_id是平台店铺ID(兼容内部id)
username是采集到的用户名(店铺账号名,如 mrsexshop)
collect_batch否批次号
shop_name / shop_location否一并更新(空值不会覆盖已有店名)
username 为空时会怎样(2026-09-29 起):不计费、不改采集状态、不共享, 返回 code:0 + accepted:false + skip_reason:empty_username。 该店铺会在下一轮继续下发,等真正采到名字再回传即可 —— 请不要为了"完成任务"回推空字符串或占位名, 那只会白跑一趟(以前会把店铺永久锁成"已采集但没名字",导致再也拿不到店铺名)。

4关键词 拉取任务 → 回推搜到的链接

GET api/keyword_collect.php?action=list&scope=need&claim=1&limit=50

功能

用户在用户端填「关键词 + 平台 + 站点 + 期望数量」后,本接口拉取待采集的关键词任务; 采集方按 keyword / platform_name / site_name 去平台搜索,把搜到的商品链接通过 keyword_callback 回推。同一个关键词被多用户追踪时只下发一条任务,回推结果自动分发给所有同轮订阅用户。

请求头

X-Api-Key: ckxxxxxxxx

请求参数

参数必填说明
action否list(默认)
scope否need(默认)=待采集或频率到期;marked=仅标记待采集;all=全部(诊断用,不做去重过滤)
claim否1=领取并生成批次号(K 前缀)
limit否默认50,最大200
batch否指定批次号继续拉取
user_id否平台级密钥下可选,只领取指定用户的关键词任务

返回要点

keyword_id / user_id / keyword / platform_name / site_name(可能为空=不限站点)/ target_count(期望采集条数)/ collect_batch / pending_total
POST api/keyword_callback.php

功能

回推关键词搜到的商品链接(数组)。回推后系统自动完成:解析店铺ID → 该用户下没有这家店就自动建店 → 链接去重入库 → 置为「待采集详情」, 随后由 collect.php 正常下发做详情采集。

请求头

X-Api-Key: ckxxxxxxxx Content-Type: application/json

请求体参数

参数必填说明
keyword_id推荐拉取时返回的 keyword_id,定位最准
platform_name / site_name / keyword否不传 keyword_id 时用这三项反查任务
user_id否平台级密钥下可选,同一关键词多用户时用于指定归属
collect_batch否关键词批次号(K 前缀)
links是搜到的商品链接数组。每项可为字符串,或对象 {product_link, product_id, main_image, shop_id, shop_name}; 缺少商品ID/店铺ID时会尝试从虾皮链接(形如 -i.{店铺ID}.{商品ID})解析,仍解析不到的条目会被跳过

返回要点

received(收到条数)/ added(实际采纳并归纳的条数)/ skipped(重复或无法归属)/ new_shops(自动新建店铺数)/ shared_users(共享到的用户数)

常见问题(采集方)

1. 拉到的任务数比"待采总数"少? 同一件商品 / 同一个店铺 / 同一个关键词被多个用户同时追踪时只下发一条任务(跨用户去重), 回推后系统自动分发给所有订阅用户,属预期行为。
2. 返回空列表并提示积分不足 / 授权到期? 该用户侧的前置条件不满足,任务会被临时扣住,用户充值或续费后自动恢复,采集方无需处理。
3. 同一条链接需要重复采吗? 不需要。按 claim=1 返回的批次,用 batch=<批次号> 继续拉取未完成部分即可,已完成的行不会再下发。
4. 回推重复提交会怎样? 店铺回推是字段覆盖,重复提交无副作用; 关键词回推的链接按「店铺 + 链接」去重,已存在的会跳过(响应里计入 skipped); 链接详情回推与评论回推现在也带判重:同一条链接的同一个 collect_batch 已经成功回推过,第二次会返回 code:0 + accepted:false + skip_reason:duplicate_retry, 不会重复入库、更不会重复扣费——这种响应说明"已收到,不需要重试",直接跳过即可。 所以:请务必带上 collect_batch,它是判重的凭据。
若响应超时不确定是否写入成功,也可以先用 api/collect.php?action=history&link_id=xxx 核对最近采集时间。
5. 采不到数据(商品下架 / 超时 / 遇到验证码)该怎么回推? 照实把错误回推上来,不要回推空壳或占位数据。系统会把该链接标成「采集失败」, 记录失败原因,并进入冷却窗口(默认 30 分钟)后自动重新排入任务;这期间不写数据、不扣费。 若推的是空壳数据,系统同样会拒收(skip_reason=collect_failed)—— 但失败状态与原因就记不下来了,运营方也无从判断是哪一类失败。 响应里的 reason 字段会写明这次为什么被判为失败。
6. 怎么拿到「店铺名」,按店铺把整店链接一次抓回来? 店铺名 = username(店铺账号名),例如 mrsexshop,用它打开 https://shopee.tw/{username} 即可枚举该店所有外显链接。获取途径(按优先级):
① 详情任务的每一行已直接带 shop_username / username_known / shop_url(collect.php,2026-09-29 起); ② shop_collect.php?action=shops&link_id=<link_id> 按商品链接反查店铺(只读、不计费); ③ shop_collect.php?action=shops&shop_id=<平台店铺ID> 单店查询; ④ shop_collect.php?action=list 只返回"还缺用户名"的店 —— 那些店本来就是需要你去采集店铺名的任务。
若 username_known=false 且任务里也没有这家店,说明店铺名还没采到, 此时用 shop_url(数字ID版店铺主页)同样能打开店铺。
7. 回推一直失败怎么办? 请把响应里的 code / msg、请求时间与批次号反馈给运营方,便于按批次对账。
8. 一次能回传多少个商品? 可以一次回传 4~50 条。把这一批的条目放进数组即可,以下写法都支持:
  · {"channel":"rpa","payload":[条目1,条目2,...]}(推荐)
  · {"results":[...]} / items / list / data / tasks / records / details
  · 顶层直接是数组 [条目1,条目2,...];或 {"payload":{"results":[...]}}
返回体:data.total / accepted / skipped / failed / credit_deducted / items[], items 里每条带 index 与自己的 accepted(失败条目还有 skip_reason 或 error)。
每条独立处理:第 3 条坏了不影响第 4 条入库与计费。个别条目失败请不要整批重推 —— 重推会命中判重闸门(不会重复计费),但白跑一趟。
9. 什么是「主动触发」? 如果某个平台的某种数据被运营方配成了主动触发, 它不会出现在普通拉取的结果里;需要带 mode=push 领取。 push 链路返回的每一行会多带 collect_mode=push 与 trigger (触发渠道:name / handler / endpoint / auth_type / has_auth / params), 你按 handler 决定走哪套接口去采。若该平台没配触发器,会返回 trigger=null 且带 trigger_hint 说明原因。
  注意:触发器里的凭证不会随任务下发(只回 auth_type 与 has_auth), 需要凭证时请写进触发器的「参数模板」,或在你自己程序里配置。
  采集完的回传接口与普通链路完全相同,无需另做一套。
10. 回传的原始 JSON 存在哪? 会按 json/{用户名}/{日期}/{批次}/{记录ID}_{字段}.json 落盘,方便按用户与批次整体导出。