商户 API 面向商户自有业务系统,提供一套围绕“项目合作、创客招募、额度校验、结算发放、交付验收、账户与开票”展开的标准接入能力。
对商户而言,实际接入的目标通常不是“调用几个接口”,而是把平台能力稳定嵌入自己的业务流程中,例如:
因此,本文档的重点不是介绍平台内部实现细节,而是从商户接入视角明确:
项目中心化:所有核心能力围绕项目展开
projectId 为主线组织数据和流程,而不是把项目当成一个可有可无的辅助字段。同步受理、异步收口:复杂链路不在同步接口中做最终承诺
recruit 属于典型异步接口。同步响应只说明“平台是否接受本次任务”,不直接代表“已经签约成功”。结果可理解:优先返回商户真正关心的业务结论
eligible=false 和 0 额度,并明确原因字段。边界清晰:区分受理结果、处理中结果与最终结果
accepted=true、status=进行中、paymentTime!=null 这类字段都不等价于“业务最终成功”。安全优先:签名、加密、权限隔离统一执行
/merchantapi/v2 路径前缀、统一请求头、统一签名与加密规则。| 术语 | 说明 |
|---|---|
| 商户 | 接入商户 API 的业务主体 |
| 创客 | 平台侧可参与项目、签约、结算的自由职业者 |
| 项目 | 平台中的业务载体,招募、额度、结算、交付物均围绕项目发生 |
| 招募批次号 | 商户为一次招募请求定义的业务批次号,用于幂等和结果关联 |
| 外部用户ID | 商户自身业务系统中标识创客的稳定业务 ID |
| 招募任务 | 平台为单个创客生成的异步处理任务,对应 taskId |
| 结算单 | 一次结算申请,包含一个或多个结算明细 |
| 结算明细 | 结算单中的单笔记录,通常对应某个创客的一笔付款 |
| 交付物 | 围绕某个结算明细上传的成果文件 |
| 可结算额度 | 创客在当前项目、当前收款方式下还能继续结算的真实金额 |
| 同税地资格 | 创客在某个税地下的实名、活体、签约等资格组合状态 |
说明 1:ID 字段统一建议按字符串处理
为避免前端或弱类型语言处理 64 位整型时出现精度丢失,所有代表 ID 的字段在接入侧都建议按字符串处理。常见字段包括:
projectIdtaskIdmakerIdsettlementIddetailIddeliverableIdinvoiceIdaccountId说明 2:projectId 以“显式传入优先,client 默认项目兜底”为基本口径
部分接口支持两种项目来源:
projectIdclient 预先绑定默认 projectId如果两者同时存在,以请求体中的 projectId 为准。
如果商户存在多项目场景,建议始终显式传入 projectId,不要依赖默认项目兜底。
说明 3:外部用户ID应视为商户侧稳定主键
在招募、查询状态、查询额度、解绑等链路中,platformUserId 不是一个可随意替换的展示字段,而是商户侧用来识别创客的重要业务标识。
商户侧应避免在正常招募链路中频繁更换同一创客的 platformUserId,否则容易触发历史绑定冲突或未决任务冲突。
| 状态码 | 状态描述 | 说明 |
|---|---|---|
| 0 | 未开始 | 项目尚未进入可执行阶段 |
| 1 | 进行中 | 当前可用于招募、额度、结算等业务 |
| 2 | 已结束 | 项目已结束,不能继续招募和结算 |
| 状态码 | 状态描述 | 说明 |
|---|---|---|
| 0 | 未审核 | 项目已创建但还未审核通过 |
| 1 | 已审核 | 项目审核通过,可进入正式使用阶段 |
| 2 | 已驳回 | 项目审核未通过 |
queryRecruitStatus 使用三态表示创客在当前项目下的状态:
| 状态值 | 状态描述 | 说明 |
|---|---|---|
UNRECRUITED | 未招募 | 创客不存在,或存在但尚未加入当前项目 |
RECRUITED_UNSIGNED | 已招募待签约 | 已加入当前项目,但实名、活体、签约任一未完成,或历史签约已无法覆盖当前项目要求 |
RECRUITED_SIGNED | 已招募已签约 | 已加入当前项目,且同税地资格完整、签约仍在有效期内 |
recruit 的最终业务结果依赖异步回调,当前商户需要重点关注以下三类异步状态:
| 状态值 | 状态描述 | 说明 |
|---|---|---|
FAILED | 失败 | 异步处理失败,商户应结合错误码和错误信息处理 |
SIGN_URL_READY | 签约链接已生成 | 已生成签约链接,等待创客完成签约 |
SIGNED | 已签约 | 已签约成功,或复用了仍然有效的历史签约结果 |
| 状态码 | 状态描述 | 说明 | 可执行操作 |
|---|---|---|---|
| 0 | 未发放 | 结算单已创建,但尚未发起支付 | 可发起支付 |
| 1 | 发放中 | 结算支付处理中 | 可查询状态 |
| 2 | 发放完成 | 结算流程已完成 | 可查询状态、查询回单 |
| 3 | 拒绝发放 | 结算被拒绝或不可继续处理 | 不可再次发起支付 |
| 状态码 | 状态描述 | 说明 |
|---|---|---|
| 1 | 待支付 | 明细已创建,等待支付 |
| 2 | 支付成功 / 已完成 | 当前实现中可获取回单的成功状态 |
| 3 | 支付失败 | 明细支付失败 |
| 4 | 拒绝支付 / 其他失败态 | 明细未成功完成 |
说明:
| 状态码 | 状态描述 | 说明 |
|---|---|---|
| 0 | 待审核 | 已上传,等待审核 |
| 1 | 已通过 | 审核通过 |
| 2 | 已驳回 | 审核驳回,通常会返回驳回原因 |
| 状态码 | 状态描述 | 说明 |
|---|---|---|
| 0 | 开票中 | 发票申请已提交,处理中 |
| 1 | 已开票 | 已完成开票 |
| 2 | 拒绝开票 | 发票申请被拒绝 |
API 的核心不是“提供很多接口”,而是“围绕项目形成一条完整业务链路”。
对商户而言,项目不是单纯用于展示的配置对象,而是业务处理的中心:
项目
├── 招募与签约
├── 创客额度
├── 结算单与结算明细
├── 交付物
└── 发票归集
这意味着商户在自己系统中接入 API 时,建议先建立“项目主数据”视角,再围绕项目串联能力:
如果商户内部系统存在“活动”“批次”“订单”“任务包”等概念,建议将这些概念映射到平台项目之上,而不是跳过项目直接建结算。
API 不再只关注“最后一笔钱怎么发出去”,而是把创客从进入项目到最终开票的关键动作串起来:
项目 -> 招募 -> 签约 -> 额度 -> 结算 -> 交付物 -> 发票
商户如果只接入结算接口,仍然可以完成基础支付动作;但如果希望减少线下人工处理和状态割裂,建议按下列顺序接入:
recruit 是 API 中最容易接错的接口。
它的同步返回,重点是告诉商户“本次任务有没有被平台接受”;它的异步回调,重点是告诉商户“这个创客最终走到了哪一步”。因此商户在系统设计上必须把两件事拆开:
建议商户系统至少保存以下字段,用于和回调对账:
recruitBatchNoprojectIdplatformUserIdtaskId商户需要形成两个固定认知:
accepted=true 不代表已经签约成功,只代表该创客的任务已进入处理链路SIGN_URL_READY 回调或状态查询结果为准,而不是以同步受理结果为准API 确实支持复用一部分历史资格,但复用不是“历史上签过就一定还能用”。
平台当前判断能否复用历史签约,核心看三件事:
当前项目的签约有效期口径为:
max(默认合同截止时间, 项目 check_date_end + 1个月)
这意味着:
check_date_end 更晚,系统可能仍会要求重新签约API 在两个方面做了明显收敛,目的是让商户系统更容易稳定接入。
第一,外部用户ID收敛为商户范围内的稳定业务主键
platformUserId 应被视为商户自己定义的稳定创客编号。platformUserId,系统会按冲突处理,而不是默默覆盖。第二,交付物上传参数收敛为 URL 模式
交付物接口当前只保留两个文件字段:
fileNamefileUrl商户只需要保证:
接入前,建议商户按下面四件事完成准备。
第一步:获取接入凭证
联系平台管理员获取以下信息:
AppIdAppSecretAESKeyclient 是否已绑定默认 projectId第二步:确认环境地址
建议的接入地址如下:
https://s.qa.gaosiqihui.com/merchantapi/v2https://s.gaosiqihui.com/merchantapi/v2建议商户将环境配置做成显式切换,不要把测试环境地址写死在代码中。
第三步:完成安全侧准备
商户至少需要完成以下能力:
X-SignrequestId 方便问题排查第四步:明确项目接入方式
很多 API 接口都依赖 projectId。如果当前 client 已绑定默认项目,部分接口可以不传 projectId;但如果商户有多项目、跨团队、跨业务线使用场景,建议统一显式传入 projectId,避免调用落到错误项目。
以下步骤按“最短联调路径”组织,建议严格按顺序执行。
先调用:
POST /merchantapi/v2/test/crypto
建议请求体(加密前):
{
"message": "Hello World! 测试V2加密功能"
}
本步骤的成功标准:
AppIdcode=0data.originalMessage 与原始明文一致signature如果这一步没有打通,不建议直接联调业务接口。
调用:
GET /merchantapi/v2/projects?page=1&size=20&status=1&auditStatus=1
本步骤主要获取:
projectIdprojectNamestatusauditStatusavailableMethodsmonthlyAvailable商户至少应确认:
调用:
GET /merchantapi/v2/projects/{projectId}
建议重点确认:
checkDateStart / checkDateEnd对需要招募和签约的业务,这一步还应重点关注 checkDateEnd,因为它会影响历史合同是否可复用。
这一阶段根据商户业务类型分成两种接入方式。
方式 A:需要招募新创客
建议顺序:
POST /merchantapi/v2/projects/queryRecruitStatusPOST /merchantapi/v2/projects/recruittaskId方式 B:创客已经入项,只需要发起结算
建议调用:
POST /merchantapi/v2/projects/makers/quota
重点确认:
eligible=truereceiveMethodQuotas[].availableQuota 足够覆盖本次结算金额创建结算单:
POST /merchantapi/v2/settlements
如未选择立即支付,后续可调用:
POST /merchantapi/v2/settlements/{settlementId}/pay
然后建议按以下顺序核对:
完成上述五步后,建议继续重点阅读:
如果商户接入的是完整业务闭环,而不是单一结算场景,建议优先把“招募接口、招募回调、额度接口、结算接口、交付物接口”放在同一轮联调中完成,这样更容易尽早发现状态流转问题。
API 中需要重点接入的异步通知如下:
| 场景 | 所属接口/配置 | 回调地址来源 | 是否必须配置 | 典型结果 |
|---|---|---|---|---|
| 项目审核结果 | POST /merchantapi/v2/projects/create | 请求体 notifyUrl | 否 | 项目审核通过 / 驳回 |
| 招募结果 | POST /merchantapi/v2/projects/recruit | 请求体 notifyUrl | 是 | FAILED / SIGN_URL_READY / SIGNED |
| 结算结果 | POST /merchantapi/v2/settlements | 请求体 notifyUrl | 否 | 结算主单和明细状态更新 |
| 充值上账结果 | 商户 API 客户端配置 | 客户端配置 rechargeNotifyUrl | 否 | 企业账户充值到账 |
| 发票结果 | POST /merchantapi/v2/invoice/apply | 请求体 notifyUrl | 否 | 开票中 / 已开票 / 拒绝开票 |
对商户而言,接入时应把这些异步通知视为“最终状态收口”机制,而不是同步接口的附属补充。
同步接口解决的是“是否受理”,异步通知解决的是“最终发生了什么”。
除个别历史兼容差异外,商户异步通知统一遵循以下规则。
HTTP POST 向商户回调地址发送 JSON Body。2xx 响应等原因发起重试。异步通知的 HTTP Body 不是直接返回业务字段,而是先包一层统一外壳:
{
"sign": "xxxxx",
"signType": "AES_ONLY",
"timestamp": "1742891000000",
"nonce": "0d7d8f1a-xxxx",
"appId": "pico_app_002",
"data": "......"
}
| 字段 | 说明 |
|---|---|
sign | 通知签名 |
signType | 当前客户端配置的签名/加密模式 |
timestamp | 毫秒时间戳 |
nonce | 随机串 |
appId | 商户应用 ID |
data | 业务数据;若开启通知加密则为密文,否则为明文 JSON |
商户处理异步通知时,建议固定按以下顺序执行:
signdata 为加密串,先解密 data通知签名与普通 API 请求签名使用同一套商户密钥体系,但签名串不同。
通知验签参与字段为:
appIdbody(即外层 data)noncesignTypetimestamp2xx 状态码,平台即视为本次通知成功。2xx,或平台发送过程中出现网络异常,平台会自动重试。1 / 2 / 4 / 5 / 10 / 20 分钟。taskId、settlementId、invoiceId、dealId 等。| 接口名称 | 请求方式 | 接口路径 | 功能描述 |
|---|---|---|---|
| 加密测试 | POST | /merchantapi/v2/test/crypto | 测试验签、解密和上下文识别 |
| 查询项目列表 | GET | /merchantapi/v2/projects | 获取商户可用项目列表 |
| 创建项目 | POST | /merchantapi/v2/projects/create | 创建项目 |
| 查询项目详情 | GET | /merchantapi/v2/projects/{projectId} | 获取项目完整详情 |
| 查询创客招募状态 | POST | /merchantapi/v2/projects/queryRecruitStatus | 查询创客在当前项目下的招募与签约状态 |
| 批量招募创客 | POST | /merchantapi/v2/projects/recruit | 批量异步招募创客 |
| 查询创客额度 | POST | /merchantapi/v2/projects/makers/quota | 查询单个创客可结算额度 |
| 批量查询创客额度 | POST | /merchantapi/v2/projects/makers/quota/batch | 批量查询创客可结算额度 |
| 上传交付物 | POST | /merchantapi/v2/projects/upload-deliverable | 上传结算明细对应交付物 |
| 查询已上传交付物 | POST | /merchantapi/v2/projects/query-deliverables | 查询结算明细下历史交付物 |
| 查询结算单列表 | GET | /merchantapi/v2/settlements | 分页查询结算单列表 |
| 查询结算单详情 | GET | /merchantapi/v2/settlements/{settlementId} | 查询结算单详情 |
| 创建结算单 | POST | /merchantapi/v2/settlements | 创建结算单 |
| 发起支付 | POST | /merchantapi/v2/settlements/{settlementId}/pay | 对已创建结算单发起支付 |
| 获取结算回单 | GET | /merchantapi/v2/settlement-details/{detailId}/receipt | 获取结算回单 |
| 查询自由职业者信息 | POST | /merchantapi/v2/makers/query | 批量查询自由职业者信息 |
| 解绑自由职业者 | POST | /merchantapi/v2/makers/unbind | 按外部用户ID解绑自由职业者 |
| 查询企业账户信息 | GET | /merchantapi/v2/account/queryMerchantAccountInfo | 查询企业账户列表与余额信息 |
| 查询可开票余额 | GET | /merchantapi/v2/invoice/queryAvailableInvoiceBalance | 查询按税地和税目归集的可开票余额 |
| 开票申请 | POST | /merchantapi/v2/invoice/apply | 发起开票申请 |
| 查询发票详情 | GET | /merchantapi/v2/invoice/myInvoice/{invoiceId} | 查询发票申请结果和附件 |
除个别内部调用场景外,商户调用接口时统一使用以下请求头:
| 请求头 | 必填 | 说明 |
|---|---|---|
X-App-Id | 是 | 平台分配的应用 ID |
X-Timestamp | 是 | 毫秒级时间戳 |
X-Nonce | 是 | 随机字符串,建议每次请求唯一 |
X-Sign | 是 | 请求签名 |
X-Encrypt-Type | POST 请求是 | 当前按 AES 接入 |
所有接口统一返回 MerchantApiResponse<T> 结构:
{
"code": 0,
"message": "成功",
"data": {},
"timestamp": "1742891000000",
"requestId": "req_xxx",
"encrypted": false,
"signature": "xxxx"
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
code | Integer | 顶层结果码,0 表示接口调用成功 |
message | String | 顶层结果描述 |
data | Object / null | 业务数据;不同接口的 data 结构不同,后续各接口章节均只展开 data 字段的完整结构 |
timestamp | Long | 响应时间戳(毫秒) |
requestId | String | 平台侧请求标识,联调和问题排查时请保留 |
encrypted | Boolean | 当前对外响应中通常为 false;未来如启用响应加密时用于标识 |
encryptedData | String | 预留字段;当前通常为空或不返回 |
signature | String | 响应签名,商户建议校验 |
{"encryptedData":"..."} 形式传输。projectId 的 POST 接口遵循“请求体优先,client 默认项目兜底”的口径。code=0 只代表请求受理成功,不代表业务最终成功。用于验证商户侧签名、AES 加密、服务端解密和响应签名链路是否正常。
POST /merchantapi/v2/test/crypto
{
"message": "Hello World! 测试V2加密功能"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| message | String | 是 | 测试消息,最长 1000 字符 |
{
"code": 0,
"message": "成功",
"data": {
"originalMessage": "Hello World! 测试V2加密功能",
"encryptionInfo": "AES加密方案"
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
| originalMessage | String | 原始消息 |
| encryptionInfo | String | 当前识别到的加密方案说明 |
分页查询当前商户名下的项目列表,可按项目状态、审核状态筛选。
GET /merchantapi/v2/projects?page=1&size=20&status=1&auditStatus=1
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | Integer | 否 | 页码,默认 1,必须大于 0 |
| size | Integer | 否 | 每页数量,默认 20,范围 1-100 |
| status | Integer | 否 | 项目状态:0-未开始,1-进行中,2-已结束 |
| auditStatus | Integer | 否 | 审核状态:0-未审核,1-已审核,2-已驳回 |
{
"code": 0,
"message": "成功",
"data": {
"total": 5,
"page": 1,
"size": 20,
"projects": [
{
"projectId": "2016422018623922178",
"projectName": "直播活动推广项目",
"projectCode": "XM100086",
"taxCompanyId": "17",
"taxCompanyName": "上海税地",
"status": 1,
"statusDesc": "进行中",
"auditStatus": 1,
"auditStatusDesc": "已审核",
"createTime": "2026-03-23T10:00:00",
"availableMethods": ["bank", "alipay"],
"currentMonth": "2026-03",
"monthlyAvailable": 5000.00
}
]
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
total | Integer | 总记录数 |
page | Integer | 当前页码 |
size | Integer | 每页数量 |
pages | Integer | 总页数 |
projects | Array | 项目摘要列表 |
projects[].projectId | String | 项目 ID |
projects[].projectName | String | 项目名称 |
projects[].projectCode | String | 项目编码 |
projects[].status | Integer | 项目状态:0-未开始、1-进行中、2-已结束 |
projects[].statusDesc | String | 项目状态描述 |
projects[].auditStatus | Integer | 审核状态:0-未审核、1-已审核、2-已驳回 |
projects[].auditStatusDesc | String | 审核状态描述 |
projects[].taxCompanyId | String | 税地 ID |
projects[].taxCompanyName | String | 税地名称 |
projects[].createTime | String | 创建时间,格式通常为 yyyy-MM-ddTHH:mm:ss |
projects[].availableMethods | Array | 当前项目支持的创客收款方式;无可用方式时返回空数组 |
projects[].currentMonth | String | 当前月份,格式 yyyy-MM |
projects[].monthlyAvailable | BigDecimal | 当前月份税地可用剩余额度摘要,单位元 |
projectId 和判断项目是否可用。monthlyAvailable 是摘要值,详细额度需查看项目详情或创客额度接口。创建单个项目。项目创建成功后,通常仍需要审核通过后才能用于正式业务。
POST /merchantapi/v2/projects/create
{
"notifyUrl": "https://merchant.example.com/callback/project-audit",
"name": "直播活动推广项目",
"content": "负责直播活动推广与线索收集",
"calculationType": "DAY",
"calculationDesc": "按天结算",
"projectBudget": 12.34,
"type": 0,
"makerNumber": 20,
"settlementRule": "验收通过后T+7结算",
"verify": "提交成果并审核通过视为验收完成",
"checkDateStart": "2026-03-25",
"checkDateEnd": "2026-03-31",
"remark": "优先安排有直播经验的创客"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| notifyUrl | String | 否 | 项目审核状态回调地址,长度不超过 200 |
| name | String | 是 | 项目名称,最长 100 |
| content | String | 是 | 项目内容,最长 1000 |
| calculationType | String | 是 | 计价方式 |
| calculationDesc | String | 是 | 计价方式描述,最长 500 |
| projectBudget | BigDecimal | 是 | 项目预算,单位万 |
| type | Integer | 否 | 当前仅支持 0 |
| makerNumber | Integer | 是 | 招募人数 |
| settlementRule | String | 是 | 结算规则,最长 100 |
| verify | String | 是 | 验收标准,最长 1000 |
| checkDateStart | String | 是 | 验收开始日期,格式 yyyy-MM-dd |
| checkDateEnd | String | 是 | 验收结束日期,格式 yyyy-MM-dd |
| remark | String | 否 | 备注,最长 200 |
{
"code": 0,
"message": "成功",
"data": {
"projectId": "1967533227101458434",
"code": "XM100086",
"projectName": "直播活动推广项目",
"auditStatus": 0,
"auditStatusDesc": "未审核",
"message": "创建成功,待审核"
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
projectId | String | 项目 ID |
code | String | 项目编号 |
projectName | String | 项目名称 |
auditStatus | Integer | 审核状态:0-未审核、1-已审核、2-已驳回;创建成功后初始固定为 0 |
auditStatusDesc | String | 审核状态描述;创建成功后通常为“未审核” |
message | String | 处理结果信息;成功时通常为“创建成功,待审核” |
如果创建项目时传入了 notifyUrl,项目审核状态发生变化后,平台会向该地址发送异步通知。
触发时机:
外层通知包:
项目审核通知使用第三章“异步通知通用规范”中的统一外层通知包。
业务 payload:
项目审核通知的业务字段与“查询项目详情接口”的响应字段保持一致,商户可直接复用项目详情的数据结构进行解析。
其中最需要重点关注的字段包括:
| 字段 | 说明 |
|---|---|
projectId | 项目 ID |
projectName | 项目名称 |
auditStatus | 审核状态:0/1/2 |
auditStatusDesc | 审核状态描述 |
rejectReason | 驳回原因;审核通过时通常为空 |
status | 项目状态 |
statusDesc | 项目状态描述 |
处理建议:
projectId 做幂等更新。auditStatus=1 时,可将项目切换到“可进入招募/额度/结算联调”的状态。auditStatus=2 时,建议保存 rejectReason 并阻断后续业务发起。获取单个项目的完整详情,包含税地、费率、收款方式额度、绑定账户摘要等信息。
GET /merchantapi/v2/projects/{projectId}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 是 | 项目 ID |
{
"code": 0,
"message": "成功",
"data": {
"projectId": "2016422018623922178",
"projectName": "直播活动推广项目",
"projectCode": "XM100086",
"taxCompanyId": "17",
"taxCompanyName": "上海税地",
"auditStatus": 1,
"auditStatusDesc": "已审核",
"status": 1,
"statusDesc": "进行中",
"projectBudget": 12.34,
"settleRate": 6.00,
"serviceRate": 1.50,
"currentMonth": "2026-03",
"monthlyQuota": 200000.00,
"monthlyUsed": 65000.00,
"monthlyAvailable": 135000.00,
"receiveMethodConfigs": [
{
"receiveMethod": "bank",
"status": 1,
"singleLimit": 50000.00,
"monthlyQuota": 100000.00,
"monthlyUsed": 35000.00,
"monthlyAvailable": 65000.00
}
],
"paymentAccounts": [
{
"merchantAccountId": "3001",
"displayName": "平安银行尾号1234",
"receiveMethod": "bank",
"amount": 120000.00,
"availableAmount": 118000.00
}
],
"deliverableRate": 75.50
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
projectId | String | 项目 ID |
projectName | String | 项目名称 |
projectCode | String | 项目编码 |
content | String | 项目内容 |
calculationType | String | 计价方式,如 DAY / WEEK / MONTH / QUARTER / YEAR / TIME / ITEM |
calculationDesc | String | 计价方式描述 |
projectBudget | BigDecimal | 项目预算,单位万元 |
type | Integer | 项目类型;当前仅支持 0-派单项目 |
auditStatus | Integer | 审核状态:0-未审核、1-已审核、2-已驳回 |
auditStatusDesc | String | 审核状态描述 |
rejectReason | String | 驳回原因;未驳回时通常为空 |
makerNumber | Integer | 招募创客数 |
settlementRule | String | 结算规则 |
verify | String | 验收标准 |
checkDateStart | String | 验收开始日期,格式 yyyy-MM-dd |
checkDateEnd | String | 验收结束日期,格式 yyyy-MM-dd |
remark | String | 备注 |
taxCompanyId | String | 税地 ID |
taxCompanyName | String | 税地名称 |
taxCompanyCode | String | 税地编码 |
taxCategoryId | String | 税目 ID |
taxCategoryName | String | 税目名称 |
settleRate | BigDecimal | 结算费率,百分制 |
serviceRate | BigDecimal | 技术服务费率,百分制 |
status | Integer | 项目状态:0-未开始、1-进行中、2-已结束 |
statusDesc | String | 项目状态描述 |
currentMonth | String | 当前月份,格式 yyyy-MM |
monthlyQuota | BigDecimal | 税地月度总额度,单位元 |
monthlyUsed | BigDecimal | 税地本月已使用额度,单位元 |
monthlyAvailable | BigDecimal | 税地本月剩余额度,单位元 |
receiveMethodConfigs | Array | 按收款方式聚合的规则额度配置 |
receiveMethodConfigs[].receiveMethod | String | 收款方式,如 bank / alipay / wechat |
receiveMethodConfigs[].status | Integer | 方式状态:1-正常、0-停用 |
receiveMethodConfigs[].singleLimit | BigDecimal | 单笔规则限额,单位元 |
receiveMethodConfigs[].monthlyQuota | BigDecimal | 月度规则额度,单位元 |
receiveMethodConfigs[].monthlyUsed | BigDecimal | 本月已使用规则额度,单位元 |
receiveMethodConfigs[].monthlyAvailable | BigDecimal | 本月剩余规则额度,单位元 |
paymentAccounts | Array | 项目绑定账户摘要 |
paymentAccounts[].merchantAccountId | String | 商户账户 ID |
paymentAccounts[].displayName | String | 账户展示名称,例如银行尾号或账号别名 |
paymentAccounts[].receiveMethod | String | 收款方式 |
paymentAccounts[].amount | BigDecimal | 账户余额参考值,单位元 |
paymentAccounts[].availableAmount | BigDecimal | 账户可用余额参考值,单位元 |
deliverableRate | BigDecimal | 交付物提交率,百分制 |
receiveMethodConfigs 反映项目规则额度。paymentAccounts 表示本项目绑定的商户账户摘要,余额字段为参考值。deliverableRate 是项目交付进度指标,不参与费率和金额计算。查询某个创客在当前项目下的招募与签约状态。
POST /merchantapi/v2/projects/queryRecruitStatus
{
"projectId": "2016422018623922178",
"phone": "13800000000",
"platformUserId": "DY20260115105692"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 否 | 请求体优先,client 绑定项目兜底 |
| phone | String | 否 | 与 platformUserId 至少传一个 |
| platformUserId | String | 否 | 与 phone 至少传一个 |
{
"code": 0,
"message": "成功",
"data": {
"projectId": "2016422018623922178",
"maskedPhone": "138****0000",
"platformUserId": "DY20260115105692",
"status": "RECRUITED_UNSIGNED",
"statusDesc": "已招募待签约"
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
projectId | String | 项目 ID |
maskedPhone | String | 脱敏手机号;若本次未能定位到手机号,则可能为空 |
platformUserId | String | 外部用户ID;若本次未能定位到外部用户ID,则可能为空 |
status | String | 招募状态:UNRECRUITED、RECRUITED_UNSIGNED、RECRUITED_SIGNED |
statusDesc | String | 招募状态描述,如“未招募”“已招募待签约”“已招募已签约” |
UNRECRUITED。项目 check_date_end + 1个月
异步受理招募任务。同步响应只表达“是否受理”,最终结果通过回调通知商户。
POST /merchantapi/v2/projects/recruit
{
"projectId": "2016422018623922178",
"recruitBatchNo": "RB202603230001",
"notifyUrl": "https://merchant.example.com/api/recruit/callback",
"redirectUrl": "https://merchant.example.com/app/sign-result",
"makers": [
{
"name": "张三",
"phone": "13812345678",
"idNumber": "310101199001011234",
"platformUserId": "DY20260115105692",
"address": "上海市浦东新区",
"platformName": "某平台",
"platformUserName": "张三",
"obversePic": "https://secure-oss.example.com/front.jpg",
"reversePic": "https://secure-oss.example.com/back.jpg",
"livenessFaceImageUrl": "https://secure-oss.example.com/face.jpg",
"livenessVideoUrl": "https://secure-oss.example.com/video.mp4"
}
]
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 否 | 请求体优先,client 绑定项目兜底 |
| recruitBatchNo | String | 是 | 招募批次号,幂等键之一,最长 64 |
| notifyUrl | String | 是 | 结果回调地址,生产环境必须为 HTTPS |
| redirectUrl | String | 否 | 签约完成后的跳转地址,最长 200 |
| makers | Array | 是 | 招募创客列表,单次最多 50 条 |
单条 makers[] 字段:
| 字段 | 必填 | 说明 |
|---|---|---|
| name | 是 | 姓名 |
| phone | 是 | 手机号 |
| idNumber | 是 | 身份证号 |
| platformUserId | 是 | 外部用户ID |
| address | 否 | 地址 |
| platformName | 否 | 平台名称 |
| platformUserName | 否 | 平台用户名 |
| obversePic | 否 | 身份证正面 URL |
| reversePic | 否 | 身份证反面 URL |
| livenessFaceImageUrl | 否 | 活体照片 URL |
| livenessVideoUrl | 否 | 活体视频 URL |
注意事项:
phone 和 platformUserId 都不能重复。obversePic 和 reversePic 必须成对传入,不能只传一个。platformUserId 被视为商户侧稳定业务标识,不允许在活跃招募链路中随意改绑。{
"code": 0,
"message": "成功",
"data": {
"projectId": "2016422018623922178",
"recruitBatchNo": "RB202603230001",
"totalCount": 2,
"acceptedCount": 1,
"rejectedCount": 1,
"results": [
{
"platformUserId": "DY20260115105692",
"maskedPhone": "138****5678",
"accepted": true,
"message": "已受理,后续结果请关注回调",
"errorCode": 0,
"taskId": "2034454171060154370"
},
{
"platformUserId": "DY20260115105693",
"maskedPhone": "139****5678",
"accepted": false,
"message": "同一请求内platformUserId不能重复",
"errorCode": 40259,
"taskId": null
}
]
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
projectId | String | 项目 ID |
recruitBatchNo | String | 招募批次号 |
totalCount | Integer | 本次请求总数 |
acceptedCount | Integer | 受理成功数量 |
rejectedCount | Integer | 同步拒绝数量 |
results | Array | 逐条处理结果 |
results[].platformUserId | String | 外部用户ID |
results[].maskedPhone | String | 脱敏手机号 |
results[].accepted | Boolean | 是否已受理 |
results[].message | String | 结果描述 |
results[].errorCode | Integer | 错误码;成功时通常为 0 |
results[].taskId | String | 招募任务 ID;accepted=true 时通常返回 |
accepted=true 只代表已受理,不代表已经签约成功。FAILEDSIGN_URL_READYSIGNEDcheck_date_end + 1个月 要求。recruitBatchNo + platformUserId 作为本次招募任务的主关联键,以 taskId 作为平台侧任务主键保存。phone 重复platformUserId 重复platformUserId 在商户范围内已稳定绑定到其他创客recruitBatchNo + platformUserId 发起的是“参数完全一致的重放请求”,系统不会重复新建任务,而是按历史任务当前状态返回结果:
招募接口的最终结果通过商户提供的 notifyUrl 回调。
回调 HTTP Body 不是直接返回业务字段,而是先包一层通知外壳:
| 外层字段 | 说明 |
|---|---|
sign | 回调签名 |
signType | 签名/加密类型 |
timestamp | 时间戳 |
nonce | 随机串 |
appId | 应用 ID |
data | 业务数据 |
说明:
data。data 不是明文 JSON,而是加密后的字符串;商户需要先解密,再解析业务字段。解密后的业务数据核心字段如下:
| 字段 | 说明 |
|---|---|
notifyType | 通知类型,固定为招募结果通知 |
recruitBatchNo | 招募批次号 |
projectId | 项目 ID |
taskId | 招募任务 ID |
platformUserId | 外部用户ID |
maskedPhone | 脱敏手机号 |
taskStatus | SIGN_URL_READY / SIGNED / FAILED |
message | 结果描述 |
signUrl | 当 taskStatus=SIGN_URL_READY 时返回签约链接 |
contractId | 当 taskStatus=SIGNED 时通常返回合同 ID |
errorCode | 错误码 |
errorMessage | 错误信息 |
finishTime | 任务完成时间 |
商户建议按以下方式处理回调:
data 为加密数据,先解密 datataskId 或 recruitBatchNo + platformUserId 做幂等更新SIGN_URL_READY 时更新待签约状态并向前端暴露签约入口SIGNED 时更新为已签约可结算,并记录 contractIdFAILED 时记录 errorCode / errorMessage 并允许人工或业务重试关于 SIGNED 状态,商户应重点理解两类典型场景:
SIGN_URL_READY,创客通过签约链接完成签约后,平台再以 SIGNED 收口最终结果因此,商户侧不应把 SIGN_URL_READY 误判为最终成功,只有收到 SIGNED 回调或查询状态明确已完成时,才应将该创客置为“已签约可结算”。
查询单个创客在当前项目下的真实可结算额度。
POST /merchantapi/v2/projects/makers/quota
{
"projectId": "2016422018623922178",
"phone": "13800000000",
"platformUserId": "DY20260115105692"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 否 | 请求体优先,client 绑定项目兜底 |
| phone | String | 否 | 与 platformUserId 至少传一个 |
| platformUserId | String | 否 | 与 phone 至少传一个 |
{
"code": 0,
"message": "成功",
"data": {
"projectId": "2016422018623922178",
"maskedPhone": "138****0000",
"platformUserId": "DY20260115105692",
"eligible": true,
"reasonCode": "ELIGIBLE",
"eligibleDesc": "可结算",
"currentMonth": "2026-03",
"totalAvailableQuota": 65000.00,
"receiveMethodQuotas": [
{
"receiveMethod": "bank",
"personalAvailableQuota": 80000.00,
"sharedAvailableQuota": 65000.00,
"availableQuota": 65000.00
}
]
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
projectId | String | 项目 ID |
maskedPhone | String | 脱敏手机号;若本次未能定位到手机号,则可能为空 |
platformUserId | String | 外部用户ID;若本次未能定位到外部用户ID,则可能为空 |
eligible | Boolean | 是否具备可结算资格 |
reasonCode | String | 资格结果码,如 ELIGIBLE / MAKER_NOT_FOUND / NOT_IN_PROJECT / QUALIFICATION_NOT_READY |
eligibleDesc | String | 资格描述 |
currentMonth | String | 当前月份,格式 yyyy-MM |
totalAvailableQuota | BigDecimal | 当前项目下单个可用收款方式可结算额度的最大值 |
receiveMethodQuotas | Array | 按项目支持的收款方式返回额度明细 |
receiveMethodQuotas[].receiveMethod | String | 收款方式 |
receiveMethodQuotas[].personalAvailableQuota | BigDecimal | 创客个人可用额度 |
receiveMethodQuotas[].sharedAvailableQuota | BigDecimal | 项目共享可用额度 |
receiveMethodQuotas[].availableQuota | BigDecimal | 真实可结算额度,取个人可用额度与共享可用额度的最小值 |
eligible=falsereasonCodeeligibleDesceligibleDesc,不要自行硬编码推断。totalAvailableQuota 是摘要值,适合快速判断“当前是否还有额度”;真正落单时仍应结合具体 receiveMethodQuotas[].availableQuota 判断。单方式额度口径:
availableQuota = min(personalAvailableQuota, sharedAvailableQuota)
按手机号或外部用户ID批量查询多个创客在项目下的额度。
POST /merchantapi/v2/projects/makers/quota/batch
{
"projectId": "2016422018623922178",
"makers": [
{ "phone": "13800000000" },
{ "platformUserId": "DY20260115105692" }
]
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 否 | 请求体优先,client 绑定项目兜底 |
| makers | Array | 是 | 创客标识列表,单次最多 50 条 |
| makers[].phone | String | 否 | 与 platformUserId 至少传一个 |
| makers[].platformUserId | String | 否 | 与 phone 至少传一个 |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
projectId | String | 项目 ID |
currentMonth | String | 当前月份,格式 yyyy-MM |
totalCount | Integer | 总条数 |
eligibleCount | Integer | 有资格条数 |
ineligibleCount | Integer | 无资格或参数异常条数 |
results | Array | 单个创客额度结果列表 |
results[].projectId | String | 项目 ID |
results[].maskedPhone | String | 脱敏手机号 |
results[].platformUserId | String | 外部用户ID |
results[].eligible | Boolean | 是否具备可结算资格 |
results[].reasonCode | String | 资格结果码 |
results[].eligibleDesc | String | 资格描述 |
results[].currentMonth | String | 当前月份,格式 yyyy-MM |
results[].totalAvailableQuota | BigDecimal | 当前项目下单个可用收款方式可结算额度的最大值 |
results[].receiveMethodQuotas | Array | 按收款方式返回的额度明细 |
results[].receiveMethodQuotas[].receiveMethod | String | 收款方式 |
results[].receiveMethodQuotas[].personalAvailableQuota | BigDecimal | 创客个人可用额度 |
results[].receiveMethodQuotas[].sharedAvailableQuota | BigDecimal | 项目共享可用额度 |
results[].receiveMethodQuotas[].availableQuota | BigDecimal | 真实可结算额度 |
results[].errorCode | Integer | 单条结果码;0 表示该条具备可结算资格 |
results[].errorMessage | String | 单条结果描述 |
code=0。errorCode / errorMessage 表达。code。按结算明细上传交付物。
商户只需要传 detailId,平台会自动反查对应项目、结算单和创客任务。
POST /merchantapi/v2/projects/upload-deliverable
{
"detailId": "2034461359380058114",
"deliveryDate": "2025-01-20",
"description": "本月工作成果交付",
"files": [
{
"fileName": "deliverable_1.jpg",
"fileUrl": "https://merchant-oss.example.com/deliverable_1.jpg"
}
]
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| detailId | String | 是 | 结算明细 ID |
| deliveryDate | String | 是 | 交付日期,格式 yyyy-MM-dd |
| description | String | 否 | 交付说明 |
| files | Array | 是 | 文件列表,至少 1 个,最多 20 个 |
| files[].fileName | String | 是 | 文件名,最长 200 |
| files[].fileUrl | String | 是 | 文件 URL,必须为 HTTPS |
{
"code": 0,
"message": "成功",
"data": {
"deliverableId": "2036730053746438146",
"detailId": "2034461359380058114",
"files": [
{
"fileId": "2036730053775798274",
"fileName": "deliverable_1.jpg",
"fileUrl": "https://oss.example.com/merchant-deliverable-xxx-file-1.jpg"
}
],
"fileCount": 1,
"uploadTime": "2026-03-25 17:01:00"
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
deliverableId | String | 交付物记录 ID |
detailId | String | 结算明细 ID |
files | Array | 文件处理结果列表 |
files[].fileId | String | 文件 ID |
files[].fileName | String | 文件名 |
files[].fileUrl | String | 平台转存后的文件访问地址;若返回的是预签名 URL,过期后请重新调用查询接口获取 |
fileCount | Integer | 文件数量 |
uploadTime | String | 上传时间,格式通常为 yyyy-MM-dd HH:mm:ss |
detailId,而不是自行用结算单号模糊关联。jpg、jpeg、png、gif、bmp、webpmp4、avi、mov、wmv、mkvpdf、doc、docx、xls、xlsx按结算明细查询该明细下历史上传的交付物记录。
POST /merchantapi/v2/projects/query-deliverables
{
"detailId": "2034461359380058114"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| detailId | String | 是 | 结算明细 ID |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
detailId | String | 结算明细 ID |
totalCount | Integer | 上传记录总数 |
deliverables | Array | 交付物上传记录列表,按上传时间倒序返回 |
deliverables[].deliverableId | String | 交付物记录 ID |
deliverables[].deliverableNo | String | 交付物编号 |
deliverables[].deliveryDate | String | 交付日期,格式 yyyy-MM-dd |
deliverables[].description | String | 交付描述 |
deliverables[].verifyStatus | Integer | 审核状态:0-待审核、1-已通过、2-已驳回 |
deliverables[].verifyStatusDesc | String | 审核状态描述 |
deliverables[].rejectReason | String | 驳回原因;仅驳回时通常返回 |
deliverables[].uploadTime | String | 上传时间 |
deliverables[].verifyTime | String | 审核时间 |
deliverables[].fileCount | Integer | 文件数量 |
deliverables[].files | Array | 文件明细列表 |
deliverables[].files[].fileId | String | 文件 ID |
deliverables[].files[].fileName | String | 文件名 |
deliverables[].files[].fileUrl | String | 文件地址;若返回的是短时效预签名 URL,过期后请重新调用查询接口获取最新地址 |
totalCount=0。分页查询结算单列表。
GET /merchantapi/v2/settlements?page=1&size=20&status=1&projectId=2016422018623922178
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | Integer | 否 | 页码,默认 1 |
| size | Integer | 否 | 每页数量,默认 20 |
| status | Integer | 否 | 结算单状态 |
| projectId | String | 否 | 项目 ID |
| settlementNo | String | 否 | 结算单号 |
| startTime | String | 否 | 开始时间,格式 yyyy-MM-ddTHH:mm:ss |
| endTime | String | 否 | 结束时间,格式 yyyy-MM-ddTHH:mm:ss,且不能晚于当前日期 |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
total | Integer | 总记录数 |
page | Integer | 当前页码 |
size | Integer | 每页数量 |
pages | Integer | 总页数 |
list | Array | 结算单列表 |
list[].settlementId | String | 结算单 ID |
list[].settlementNo | String | 系统结算单号 |
list[].projectId | String | 项目 ID |
list[].projectName | String | 项目名称 |
list[].taxCompanyName | String | 税地名称 |
list[].receiveMethod | String | 收款方式 |
list[].totalAmount | BigDecimal | 结算总金额 |
list[].totalCount | Integer | 结算总笔数 |
list[].status | Integer | 结算状态:0-未发放、1-发放中、2-发放完成、3-拒绝发放 |
list[].statusDesc | String | 结算状态描述 |
list[].createTime | String | 创建时间 |
list[].paymentTime | String | 支付时间 |
list[].completeTime | String | 完成时间 |
list[].successCount | Integer | 成功笔数 |
list[].failCount | Integer | 失败笔数 |
projectId、状态过滤条件、时间范围和结算单号是否一致。startTime 和 endTime 时,要求 startTime <= endTime。endTime 不能大于当前日期。查询单个结算单的主信息和明细信息。
GET /merchantapi/v2/settlements/{settlementId}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| settlementId | String | 是 | 结算单 ID |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
settlementId | String | 结算单 ID |
settlementNo | String | 结算单编号 |
projectId | String | 项目 ID |
projectName | String | 项目名称 |
taxCompanyName | String | 税地名称 |
receiveMethod | String | 收款方式 |
totalAmount | BigDecimal | 提交总金额 |
totalCount | Integer | 总笔数 |
status | Integer | 结算状态 |
statusDesc | String | 结算状态描述 |
createTime | String | 创建时间 |
paymentTime | String | 支付时间 |
completeTime | String | 完成时间 |
remark | String | 备注 |
successCount | Integer | 成功笔数 |
failCount | Integer | 失败笔数 |
details | Array | 结算明细列表 |
details[].detailId | String | 明细 ID |
details[].detailNo | String | 明细编号 |
details[].merchantDetailNo | String | 商户结算明细号 |
details[].amount | BigDecimal | 提交金额 |
details[].idCardHash | String | 身份证哈希值 |
details[].status | Integer | 明细状态:1-待处理、2-处理中、3-成功、4-失败 |
details[].paymentTime | String | 支付时间 |
details[].failureReason | String | 失败原因 |
details[].remark | String | 备注 |
merchantDetailNo 作为商户侧明细主键,不建议依赖身份证相关字段做关联。创建结算单。
POST /merchantapi/v2/settlements
{
"projectId": "2016422018623922178",
"merchantSettlementNo": "MERCHANT_SETTLEMENT_001",
"receiveMethod": "bank",
"immediatePay": true,
"remark": "2026年3月技术服务费",
"notifyUrl": "https://merchant.example.com/api/settlement/callback",
"details": [
{
"merchantDetailNo": "MERCHANT_DETAIL_001",
"amount": 5000.00,
"phone": "13812345678",
"platformUserId": "DY20260115105692",
"paymentAccount": {
"accountNo": "6222021234567890123",
"accountName": "张三",
"phone": "13812345678"
},
"remark": "3月技术服务费"
}
]
}
顶层参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 否 | 请求体优先,client 绑定项目兜底 |
| merchantSettlementNo | String | 是 | 商户结算单号,长度 1-64 |
| receiveMethod | String | 是 | bank / alipay / wechat |
| immediatePay | Boolean | 否 | 是否立即支付;当前默认 false |
| remark | String | 否 | 结算备注,最长 200 |
| notifyUrl | String | 否 | 异步通知地址,最长 200 |
| details | Array | 是 | 结算明细列表,至少 1 条,最多 200 条 |
单条 details[] 参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| merchantDetailNo | String | 是 | 商户明细号 |
| amount | BigDecimal | 是 | 结算金额 |
| makerId | String | 否 | 创客 ID;若未传,则至少需要传 phone 或 platformUserId 之一用于定位创客 |
| phone | String | 否 | 手机号,与 platformUserId 至少传一个 |
| platformUserId | String | 否 | 外部用户ID,与 phone 至少传一个 |
| paymentAccount | Object | 是 | 收款账户信息 |
| remark | String | 否 | 明细备注 |
paymentAccount 参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| accountNo | String | 是 | 收款账号 |
| accountName | String | 否 | 账户名 |
| phone | String | 否 | 预留手机号 |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
settlementId | String | 结算单 ID |
settlementNo | String | 系统结算单号 |
merchantSettlementNo | String | 商户结算单号 |
projectId | String | 项目 ID |
projectName | String | 项目名称 |
taxCompanyName | String | 税地名称 |
receiveMethod | String | 收款方式 |
totalAmount | BigDecimal | 结算总金额 |
totalCount | Integer | 结算总笔数 |
totalTax | BigDecimal | 试算税费合计 |
totalNetAmount | BigDecimal | 税后实发金额合计 |
status | Integer | 结算状态:0-未发放、1-发放中、2-发放完成、3-拒绝发放 |
statusDesc | String | 结算状态描述 |
createTime | String | 创建时间 |
remark | String | 结算备注 |
paymentInitiated | Boolean | 是否已发起立即支付 |
paymentFailureReason | String | 立即支付失败原因;仅 paymentInitiated=false 时可能返回 |
details | Array | 结算明细列表 |
details[].detailId | String | 明细 ID |
details[].detailNo | String | 系统明细编号 |
details[].merchantDetailNo | String | 商户结算明细号 |
details[].idCardHash | String | 证件号哈希 |
details[].amount | BigDecimal | 结算金额 |
details[].tax | BigDecimal | 试算税费 |
details[].netAmount | BigDecimal | 税后实发金额 |
details[].status | Integer | 明细状态:1-待支付、2-支付中、3-支付成功、4-支付失败 |
details[].paymentTime | String | 支付时间 |
details[].failureReason | String | 失败原因 |
details[].remark | String | 明细备注 |
availableQuota 足够覆盖结算金额merchantSettlementNo 和 merchantDetailNo 都应由商户自行保证稳定唯一,避免幂等冲突。makerId 的情况下,商户至少需要保证 phone 或 platformUserId 中有一个能稳定定位到目标创客。如果创建结算单时传入了 notifyUrl,后续结算状态变化时,平台会向该地址发送异步通知。
重要:
POST /merchantapi/v2/settlements/{settlementId}/pay 本身不再单独接收新的 notifyUrl。适用场景:
外层通知包:
结算结果通知使用第三章“异步通知通用规范”中的统一外层通知包。
业务 payload 核心字段:
| 字段 | 说明 |
|---|---|
settlementId | 结算单 ID |
settlementNo | 平台结算单号 |
merchantSettlementNo | 商户结算单号 |
projectId | 项目 ID |
receiveMethod | 收款方式 |
totalAmount | 结算总金额 |
totalNetAmount | 税后总金额 |
totalTax | 总税费 |
status | 结算单状态:0/1/2/3 |
statusDesc | 结算状态描述 |
paymentTime | 支付时间 |
completeTime | 完成时间 |
successCount | 成功笔数 |
failCount | 失败笔数 |
detailList[] | 明细结果列表 |
detailList[] 常见字段:
| 字段 | 说明 |
|---|---|
detailId | 明细 ID |
detailNo | 平台明细号 |
merchantDetailNo | 商户明细号 |
amount | 金额 |
netAmount | 税后实发金额 |
status | 明细状态 |
statusDesc | 明细状态描述 |
failReason | 失败原因 |
completeTime | 明细完成时间 |
处理建议:
settlementId 或 merchantSettlementNo 更新主单,再按 merchantDetailNo 更新明细。paymentInitiated=true 判断支付成功。对已创建的结算单发起支付。
POST /merchantapi/v2/settlements/{settlementId}/pay
{
"confirmPay": true
}
Path 参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| settlementId | String | 是 | 结算单 ID,在 URL 路径中传入 |
请求体参数(需加密):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| confirmPay | Boolean | 是 | 是否确认发起支付 |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
settlementId | String | 结算单 ID |
settlementNo | String | 系统结算单号 |
projectId | String | 项目 ID |
projectName | String | 项目名称 |
receiveMethod | String | 收款方式 |
status | Integer | 结算状态:1-待支付、2-支付中、3-支付成功、4-支付失败 |
paymentStatus | String | 支付状态,如 PENDING / PROCESSING / COMPLETED / REJECTED / UNKNOWN |
paymentTime | String | 发起支付时间 |
expectedTime | String | 预计完成时间 |
totalAmount | BigDecimal | 结算总金额 |
totalCount | Integer | 总笔数 |
successCount | Integer | 成功笔数 |
failCount | Integer | 失败笔数 |
processingCount | Integer | 处理中笔数 |
details | Array | 结算明细列表 |
details[].detailId | String | 明细 ID |
details[].detailNo | String | 系统明细编号 |
details[].merchantDetailNo | String | 商户结算明细号 |
details[].amount | BigDecimal | 结算金额 |
details[].status | Integer | 明细状态:1-待支付、2-支付中、3-支付成功、4-支付失败 |
details[].paymentTime | String | 支付时间 |
details[].failureReason | String | 失败原因 |
details[].remark | String | 备注 |
paymentStatus 当前常见取值:
| 取值 | 含义 |
|---|---|
PENDING | 待支付 |
PROCESSING | 支付处理中 |
COMPLETED | 支付完成 |
REJECTED | 已拒绝或不可继续处理 |
UNKNOWN | 未识别状态 |
confirmPay 的作用是显式确认本次支付动作,建议商户仅在人工确认或流程节点明确时调用。按结算明细获取回单文件。
GET /merchantapi/v2/settlement-details/{detailId}/receipt
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| detailId | String | 是 | 结算明细 ID |
{
"code": 0,
"message": "成功",
"data": {
"detailId": "3024091600001001",
"detailNo": "DTL202409160001",
"receiptNo": "REC202409160001",
"receiptContent": "JVBERi0xLjQKJeLjz9...",
"receiptType": "PDF",
"fileName": "回单_DTL202409160001.pdf",
"fileSize": 102400,
"generateTime": "2025-09-16 10:30:00"
}
}
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
detailId | String | 结算明细 ID |
detailNo | String | 结算明细编号 |
receiptNo | String | 回单编号 |
receiptContent | String | 回单内容(Base64) |
receiptType | String | 回单类型,如 PDF |
fileName | String | 文件名称 |
fileSize | Long | 文件大小,单位字节 |
generateTime | String | 回单生成时间 |
按手机号列表或外部用户ID列表批量查询自由职业者信息。
POST /merchantapi/v2/makers/query
{
"phoneNumbers": ["13812345678", "13912345678"]
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| phoneNumbers | Array | 否 | 手机号列表,最多 50 个。与 platformUserIds 二选一 |
| phoneNumbers[] | String | 否 | 单个手机号 |
| platformUserIds | Array | 否 | 外部用户ID列表,最多 50 个。与 phoneNumbers 二选一 |
| platformUserIds[] | String | 否 | 单个外部用户ID |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
makers | Array | 自由职业者信息列表 |
makers[].makerId | String | 创客 ID;查询成功时返回 |
makers[].name | String | 姓名(脱敏) |
makers[].idCard | String | 证件号(脱敏) |
makers[].idType | String | 证件类型 |
makers[].country | String | 国家或地区代码 |
makers[].address | String | 地址 |
makers[].phone | String | 联系电话(脱敏) |
makers[].platformUserId | String | 外部用户ID |
makers[].platformName | String | 平台名称 |
makers[].platformUserName | String | 平台用户名(脱敏) |
makers[].status | Integer | 状态:1-正常、0-禁用 |
makers[].taxCompanyQualifications | Array | 创客税地资格信息 |
makers[].taxCompanyQualifications[].taxCompanyId | String | 税地 ID |
makers[].taxCompanyQualifications[].isRealNamed | Boolean | 是否已完成税地实名认证 |
makers[].taxCompanyQualifications[].realNameTime | String | 税地实名通过时间 |
makers[].taxCompanyQualifications[].liveness | Boolean | 是否已完成税地活体认证 |
makers[].taxCompanyQualifications[].livenessTime | String | 税地活体通过时间 |
makers[].taxCompanyQualifications[].signStatus | Integer | 税地签约状态:0-未签约、1-已签约、2-已过期、3-签约中 |
makers[].taxCompanyQualifications[].signStatusDesc | String | 税地签约状态描述 |
makers[].taxCompanyQualifications[].signTime | String | 税地签约时间 |
makers[].createTime | String | 创建时间 |
makers[].updateTime | String | 更新时间 |
makers[].errorCode | String | 单条错误码;查询成功时通常为空 |
makers[].errorMessage | String | 单条错误信息;查询成功时通常为空 |
errorCode / errorMessage。phoneNumbers 和 platformUserIds 两者至少传一种,但不能同时传。platformUserId 查。按外部用户ID解绑自由职业者。
POST /merchantapi/v2/makers/unbind
{
"platformUserId": "USERID_001"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| platformUserId | String | 是 | 外部用户ID |
{
"code": 0,
"message": "成功",
"data": null
}
该接口成功时 data 固定返回 null。
platformUserId 异常绑定场景。查询商户企业账户列表及其金额信息。
GET /merchantapi/v2/account/queryMerchantAccountInfo
无业务请求体。
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
accountList | Array | 商户账户列表 |
accountList[].accountId | String | 账户 ID |
accountList[].accountType | String | 账户类型(展示字段,如银行卡/支付宝/微信支付,不建议作为稳定枚举依赖) |
accountList[].accountUserName | String | 账户持有人姓名 |
accountList[].accountUserIdCard | String | 账户持有人身份证号 |
accountList[].account | String | 账户号 |
accountList[].accountName | String | 账户名称 |
accountList[].bankName | String | 开户行名称 |
accountList[].rechargeAccount | String | 充值账号,部分渠道或配置下可能为空 |
accountList[].rechargeAccountName | String | 充值账号名称,部分渠道或配置下可能为空 |
accountList[].availableAmount | BigDecimal | 可用金额 |
accountList[].settleAmount | BigDecimal | 结算中税后金额 |
accountList[].otherAmount | BigDecimal | 结算中其他金额 |
accountList[].freezeAmount | BigDecimal | 冻结金额 |
accountType 当前返回展示值,不保证可作为长期稳定枚举使用;如需程序分支,建议不要仅依赖该字段文案。充值上账通知属于企业账户维度的异步通知,不通过业务请求体传入回调地址,而是由平台在商户 API 客户端配置中维护 rechargeNotifyUrl。
触发时机:
回调地址来源:
rechargeNotifyUrl外层通知包:
充值上账通知使用第三章“异步通知通用规范”中的统一外层通知包。
业务 payload:
{
"merchantId": "1234567890",
"amount": 100.00,
"accountNo": "6222021234567890123",
"accountName": "XX有限公司",
"counterpartyAccountNo": "6217000012345678901",
"counterpartyAccountName": "付款方有限公司",
"dealTime": "2026-03-25 10:10:10",
"dealId": "R202603250001",
"zfCode": "bank",
"remark": "充值成功"
}
| 字段 | 说明 |
|---|---|
merchantId | 商户 ID |
amount | 上账金额 |
accountNo | 充值到账账户号 |
accountName | 充值到账账户名称 |
counterpartyAccountNo | 交易对方账户号 |
counterpartyAccountName | 交易对方账户名称 |
dealTime | 上账时间 |
dealId | 交易流水号 |
zfCode | 支付通道,如 bank / alipay / wechat |
remark | 备注 |
处理建议:
dealId 作为上账通知的主幂等键。查询按税地和税目归集的可开票余额。
GET /merchantapi/v2/invoice/queryAvailableInvoiceBalance
无业务请求体。
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
taxCompanyData | Array | 税地公司数据列表 |
taxCompanyData[].taxCompanyId | String | 税地公司 ID |
taxCompanyData[].taxCompanyName | String | 税地公司名称 |
taxCompanyData[].invoiceDataList | Array | 该税地下可开票税目列表 |
taxCompanyData[].invoiceDataList[].taxCategoryName | String | 税目名称 |
taxCompanyData[].invoiceDataList[].hasInvoiceFee | BigDecimal | 已开票金额,单位元 |
taxCompanyData[].invoiceDataList[].applyInvoiceFee | BigDecimal | 申请中金额,单位元 |
taxCompanyData[].invoiceDataList[].ableInvoiceFee | BigDecimal | 可开票金额,单位元 |
发起开票申请。
POST /merchantapi/v2/invoice/apply
{
"projectId": "2016422018623922178",
"outSettlementNoList": ["JS10001884", "JS10001885"],
"invoiceType": 1,
"invoiceAddress": "上海市浦东新区XXX路88号",
"invoicePhone": "021-12345678",
"invoiceAcctNo": "3100000123456789",
"invoiceBankName": "招商银行上海分行",
"remark": "请尽快开票",
"notifyUrl": "https://merchant.example.com/api/invoice/callback"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| projectId | String | 条件必填 | 请求体优先;未传时仅在 client 已绑定默认项目时可省略。多项目商户建议始终显式传入 |
| outSettlementNoList | Array | 是 | 结算单编号列表 |
| outSettlementNoList[] | String | 是 | 单个结算单编号 |
| invoiceType | Integer | 否 | 当前默认 1,表示专票 |
| invoiceAddress | String | 否 | 发票抬头地址 |
| invoicePhone | String | 否 | 发票抬头电话 |
| invoiceAcctNo | String | 否 | 发票抬头银行账户 |
| invoiceBankName | String | 否 | 发票抬头开户行 |
| remark | String | 否 | 备注 |
| notifyUrl | String | 否 | 通知地址,最长 200 |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
invoiceId | String | 发票 ID |
taxCompanyId | String | 税地公司 ID |
taxCategoryName | String | 税目名称 |
invoiceAmount | BigDecimal | 发票金额 |
invoiceType | Integer | 发票类型;当前默认 1-专票 |
invoiceAddress | String | 发票抬头地址 |
invoicePhone | String | 发票抬头电话 |
invoiceAcctNo | String | 发票抬头银行账户 |
invoiceBankName | String | 发票抬头开户行 |
remark | String | 审核意见或备注 |
invoiceStatus | Integer | 开票状态:0-开票中、1-已开票、2-拒绝开票 |
fileList | Array | 发票附件列表 |
fileList[].fileName | String | 文件名 |
fileList[].fileUrl | String | 文件地址 |
outSettlementNoList 中的结算单必须属于当前商户和当前项目。如果开票申请时传入了 notifyUrl,后续发票状态变化后,平台会向该地址发送异步通知。
触发时机:
外层通知包:
发票结果通知使用第三章“异步通知通用规范”中的统一外层通知包。
业务 payload:
发票结果通知的业务字段与“查询发票详情接口”的响应字段保持一致,商户可直接复用发票详情的数据结构进行解析。
核心字段通常包括:
| 字段 | 说明 |
|---|---|
invoiceId | 发票 ID |
taxCompanyId | 税地 ID |
taxCategoryName | 税目名称 |
invoiceAmount | 发票金额 |
invoiceType | 发票类型 |
remark | 审核意见或备注 |
invoiceStatus | 发票状态:0开票中 / 1已开票 / 2拒绝开票 |
fileList[] | 发票附件列表 |
处理建议:
invoiceId 做幂等更新。invoiceStatus=1 时,再处理 fileList 中的发票附件展示或归档。按发票 ID 查询发票详情和附件。
GET /merchantapi/v2/invoice/myInvoice/{invoiceId}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| invoiceId | String | 是 | 发票 ID |
以下仅展开 data 字段的完整结构:
| 字段 | 类型 | 说明 |
|---|---|---|
invoiceId | String | 发票 ID |
taxCompanyId | String | 税地公司 ID |
taxCategoryName | String | 税目名称 |
invoiceAmount | BigDecimal | 发票金额 |
invoiceType | Integer | 发票类型;当前默认 1-专票 |
invoiceAddress | String | 发票抬头地址 |
invoicePhone | String | 发票抬头电话 |
invoiceAcctNo | String | 发票抬头银行账户 |
invoiceBankName | String | 发票抬头开户行 |
remark | String | 审核意见或备注 |
invoiceStatus | Integer | 开票状态:0-开票中、1-已开票、2-拒绝开票 |
fileList | Array | 发票附件列表 |
fileList[].fileName | String | 文件名 |
fileList[].fileUrl | String | 文件地址 |
fileList 获取文件下载地址。invoiceStatus=已开票 作为展示前提。所有接口调用都需要在请求头中携带认证参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
X-App-Id | String | 是 | 应用 ID |
X-Timestamp | String | 是 | 毫秒时间戳,建议 5 分钟内有效 |
X-Nonce | String | 是 | 随机字符串,用于防重放 |
X-Sign | String | 是 | 请求签名 |
X-Encrypt-Type | String | POST 请求是 | 当前按 AES 对接 |
商户需要使用 HMAC-SHA256 对请求进行签名。
签名参与参数:
timestampnoncebody(POST 请求时为加密后的完整请求体字符串;GET 请求无 body 时不参与)POST 请求示例签名串:
body={"encryptedData":"..."}&nonce=abc123×tamp=1742891000000
GET 请求示例签名串:
nonce=abc123×tamp=1742891000000
签名公式:
signature = HMAC_SHA256(appSecret, signString).toLowerCase()
响应数据为明文返回,但带签名。
商户收到响应后,建议验证响应签名,以确保:
建议商户统一封装一层 SDK 或网关能力,至少包含:
requestId 透传日志当前 API 商户接入文档默认按 AES 方式对接。
说明:
AES 模式下,请求体通常为:
{
"encryptedData": "Base64编码的密文"
}
响应统一为明文 JSON + 签名:
{
"code": 0,
"message": "成功",
"data": {},
"timestamp": "1742891000000",
"requestId": "req_xxx",
"signature": "xxxx"
}
AppSecretX-Timestamp 超时、nonce 重复、签名不匹配的请求都应视为非法请求| 环境类型 | API地址 | 用途 | 注意事项 |
|---|---|---|---|
| 测试环境 | https://s.qa.gaosiqihui.com/merchantapi/v2 | 功能测试、联调测试 | 数据仅用于测试 |
| 生产环境 | https://s.gaosiqihui.com/merchantapi/v2 | 正式业务 | 请使用真实商户凭证 |
建议商户在环境切换时同步检查以下配置:
AppId / AppSecret / AESKeyprojectId| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 0 | 成功 | - |
| 40001 | 缺少必要认证参数 | 检查请求头 |
| 40002 | 请求已过期 | 检查时间戳 |
| 40003 | 无效的 AppId | 检查 AppId |
| 40004 | 客户端已被禁用 | 联系平台 |
| 40005 | 签名验证失败 | 检查签名算法和密钥 |
| 40006 | IP 地址未授权 | 检查客户端 IP 白名单 |
| 40007 | 数据解密失败 | 检查 AES 密钥和加密方式 |
| 40008 | 参数验证失败 | 检查请求体格式和字段类型 |
| 40009 | 请求频率超限 | 降低请求频率后重试 |
| 40010 | Nonce 重复 | 使用新的随机串 |
| 40011 | 渠道商客户端需要指定商户 ID | 检查渠道商客户端配置 |
| 40012 | 渠道商客户端商户未绑定 | 联系平台检查绑定关系 |
| 40602 | 商户不存在 | 检查商户配置 |
| 40603 | 商户状态异常,无法访问 API | 联系平台处理商户状态 |
| 50000 | 系统内部错误 | 稍后重试 |
| 50001 | 业务处理异常 | 查看 message 后重试或联系平台 |
处理建议:
40001-40012 通常属于接入层问题,应先检查请求头、签名、加密、时间戳和客户端配置。40602-40603 属于商户或客户端配置问题,应联系平台确认商户配置状态。50000-50001 不建议立即高频重试,建议保留 requestId 后联系平台排查。| 错误码 | 说明 |
|---|---|
| 40101 | 项目不存在 |
| 40102 | 项目已结束 |
| 40105 | 项目未配置收款方式 |
| 40107 | 项目不属于当前商户 |
| 40110 | 项目 ID 不能为空且必须大于 0 |
| 40113-40125 | 创建项目字段校验失败 |
| 40126 | 项目尚未审核通过 |
| 40127 | 回调地址不能为空 |
| 40128 | 回调地址长度不能超过 200 字符 |
| 40130 | 税地配置有误,请联系客服 |
| 40138 | 页码必须大于 0 |
| 40139 | 每页数量必须在 1-100 之间 |
| 40140 | 项目状态参数错误 |
| 40141 | 手机号和外部用户ID至少传一个 |
| 40142 | 手机号和外部用户ID匹配到的创客不一致 |
| 40143 | 生产环境回调地址必须为 HTTPS |
| 40144 | 跳转地址长度不能超过 200 字符 |
| 40145 | 项目审核状态参数错误 |
| 40146 | 验收结束时间必须晚于当前时间 |
| 错误码 | 说明 |
|---|---|
| 40203 | 必填字段缺失 |
| 40204 | 批量数量超限 |
| 40221 | 手机号格式不正确 |
| 40224 | 外部用户ID长度不能超过 100 字符 |
| 40229 | 交付文件名称不能为空 |
| 40230 | 交付文件名称过长 |
| 40238 | 交付日期不能为空 |
| 40239 | 交付日期格式错误 |
| 40240 | 交付文件列表不能为空 |
| 40241 | 单次最多上传 20 个交付文件 |
| 40242 | 交付文件地址不能为空 |
| 40243 | 交付文件地址必须使用 HTTPS |
| 40253 | 创客尚未参与项目,不能上传交付物 |
| 40254 | 招募批次号不能为空 |
| 40255 | 招募批次号长度不能超过 64 字符 |
| 40256 | 招募创客列表不能为空 |
| 40257 | 身份证正反面图片必须同时传入 |
| 40259 | 同一请求内 platformUserId 不能重复 |
| 40262 | 同一招募任务请求参数不一致 |
| 40263 | 同一请求内手机号不能重复 |
| 40264 | 当前项目下已有进行中的招募任务 |
| 错误码 | 说明 |
|---|---|
| 40301 | 商户结算单号重复 |
| 40303 | 结算单或关联记录不存在 |
| 40312 | 无权操作当前结算相关数据 |
| 40313 | 结算明细或交付物明细不存在 |
| 40316-40334 | 创建结算单字段校验失败 |
| 40335 | 当前结算单打款失败,请勿再次操作 |
| 错误码 | 说明 |
|---|---|
| 40403 | 文件数量超限 |
| 40404 | 不支持的文件格式 |
部分额度场景不通过顶层错误码表达,而是通过业务字段表达:
| 字段 | 含义 |
|---|---|
eligible=false | 当前不具备可结算资格 |
reasonCode=MAKER_NOT_FOUND | 未找到创客 |
reasonCode=NOT_IN_PROJECT | 未加入项目 |
reasonCode=QUALIFICATION_NOT_READY | 未完成税地资格 |
说明:
这类情况不代表接口失败,而代表“业务上当前不可继续结算”。
商户应把它们当作可展示、可流转的业务状态,而不是统一当作系统异常处理。
| 错误码 | 说明 |
|---|---|
| 60001 | 申请开票金额超过可开票金额 |
| 60002 | 发票不存在 |
| 60003 | 可开票金额为 0 |
说明:
50001 + message 返回具体原因,例如“结算单不属于当前商户/项目”“结算单开票中或已开票”。50001,再结合 message 做排查和兜底提示。| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 50000 | 系统内部错误 | 稍后重试 |
| 50001 | 业务处理异常 | 结合 message 排查 |
用于验证商户侧签名、AES 加密、服务端解密和响应签名链路。
POST /merchantapi/v2/test/crypto
原始业务数据:
{
"message": "Hello World! 测试V2加密功能"
}
加密请求体示例:
{
"encryptedData": "U2FsdGVkX1+..."
}
{
"code": 0,
"message": "成功",
"data": {
"originalMessage": "Hello World! 测试V2加密功能",
"encryptionInfo": "AES加密方案"
},
"timestamp": "1742891000000",
"requestId": "req_xxx",
"signature": "xxxx"
}
| 错误码 | 说明 |
|---|---|
| 40007 | 解密失败 |
| 40008 | 参数验证失败 |
| 50000 | 系统处理异常 |
多项目场景请始终显式传入 projectId
默认项目兜底适合单项目商户;一旦商户存在多项目并行,建议所有关键接口都显式传 projectId。
招募同步返回不是最终结果
accepted=true 只代表平台接受了任务。商户必须处理异步回调,才能知道是否生成签约链接、是否已签约、为什么失败。
历史签约能否复用,取决于是否覆盖当前项目的结束时间要求
当前口径不是“签过就算”,而是“历史合同是否仍覆盖 check_date_end + 1个月 的要求”。
platformUserId 应作为商户范围内稳定唯一的业务标识
不建议在正常招募过程中反复更换同一创客的 platformUserId。误绑场景应通过解绑接口处理。
额度为 0 不一定是接口异常
在额度接口中,创客不存在、未入项、未完成资格,都会以 code=0 返回,只是在 eligible / reasonCode / eligibleDesc 中体现业务结论。
交付物接口只接受 HTTPS URL
商户不需要再上传 Base64 文件内容,但必须保证 URL 在平台处理时可以访问,且文件内容与业务描述一致。
账户摘要和账户主数据不是同一口径
项目详情中的账户余额用于项目视角展示,企业账户接口才是账户维度的主要查询入口。
联调和问题排查时请保留 requestId
一旦出现加密、签名、业务状态不一致等问题,requestId 是平台排查的第一关键信息。