# 格物知心 · 开放平台 · 接口完整说明 > 每个对外接口的入参、出参与示例,84 个接口。索引与接入流程见 https://gowu.net/open/llms.txt;人看的文档见 https://gowu.net/open/docs。 > 含全部场景,每个接口标了适用场景;只看一个场景请加 ?scene=welfare / procurement / consumer(员工福利购物 / 企业采购 / 消费者购物)。 ## 通用约定 - API Base URL:`https://api.gowu.net`,路径以 `/v1` 开头。请求体 JSON(`content-type: application/json`),金额单位元(企业额度 100 = 1 元)。 - 鉴权:请求头 `x-app-key`;appKey 配了 `app_secret` 时所有请求须签名(`x-timestamp`、`x-nonce`、`x-sign-version: 2`、`x-signature`,算法见 https://gowu.net/open/docs/rest/auth)。「用户态」接口另带 `x-open-user`(你系统里的用户 ID,取自服务端登录态)。 - 错误统一为 `{ "code": "...", "message": "..." }`:401 签名 / appKey 不对,403 没开通该接口,429 限流(按 Retry-After 重试);各接口的业务错误列在该接口下。 - 字段表里 `a.b` 是嵌套字段,`a[].b` 是数组元素的字段;示例里 `"string"` / `0` 是占位值。 ## 企业与员工 企业在开发者控制台申请正式接入时录入,平台审批通过后建好并归属你的 appKey。你的服务端查到自己的企业后,把你的用户绑成员工、设管理员;员工的 userId 就是他之后请求时放进 x-open-user 的值。 ### `GET /v1/partner/orgs` — 你的企业(审批通过后由平台建好):orgId、审核状态 鉴权:服务端签名;适用场景:员工福利购物 / 企业采购 你的企业——审批通过后由平台建好,归属当前 appKey,这里查到 `orgId` 后再绑定员工。按创建时间倒序,最多 200 条,不分页。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].orgId | string | | | items[].name | string | | | items[].status | string | pending = 待平台审核;active 后才能充值与下单。可选值:`pending` / `active` / `disabled` | | items[].unifiedCreditCode | string | | | items[].shortName | string | | | items[].contactName | string | | | items[].adminEmail | string | | | items[].region | string | | | items[].invoice | object | | | items[].invoice.title | string | 发票抬头,缺省 = 企业名称 | | items[].invoice.taxNo | string | 税号,固定等于统一社会信用代码 | | items[].invoice.bankName | string | | | items[].invoice.bankAccount | string | | | items[].invoice.address | string | | | items[].invoice.phone | string | | | items[].invoiceReady | boolean | 抬头与税号都已具备 | | items[].poolBalance | number | 企业额度池余额(100 = 1 元) | | items[].memberCount | integer | | | items[].createdAt | string | | **响应示例** ```json { "items": [ { "orgId": "string", "name": "string", "status": "pending", "unifiedCreditCode": "string", "shortName": "string", "contactName": "string", "adminEmail": "string", "region": "string", "invoice": { "title": "string", "taxNo": "string", "bankName": "string", "bankAccount": "string", "address": "string", "phone": "string" }, "invoiceReady": true, "poolBalance": 0, "memberCount": 0, "createdAt": "string" } ] } ``` --- ### `GET /v1/partner/orgs/{orgId}` — 企业详情:审核状态、开票信息、额度池余额 鉴权:服务端签名;适用场景:员工福利购物 / 企业采购 轮询它看审核状态(status 从 pending 变为 active)。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | orgId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | org | object | | | org.orgId | string | | | org.name | string | | | org.status | string | pending = 待平台审核;active 后才能充值与下单。可选值:`pending` / `active` / `disabled` | | org.unifiedCreditCode | string | | | org.shortName | string | | | org.contactName | string | | | org.adminEmail | string | | | org.region | string | | | org.invoice | object | | | org.invoice.title | string | 发票抬头,缺省 = 企业名称 | | org.invoice.taxNo | string | 税号,固定等于统一社会信用代码 | | org.invoice.bankName | string | | | org.invoice.bankAccount | string | | | org.invoice.address | string | | | org.invoice.phone | string | | | org.invoiceReady | boolean | 抬头与税号都已具备 | | org.poolBalance | number | 企业额度池余额(100 = 1 元) | | org.memberCount | integer | | | org.createdAt | string | | **响应示例** ```json { "org": { "orgId": "string", "name": "string", "status": "pending", "unifiedCreditCode": "string", "shortName": "string", "contactName": "string", "adminEmail": "string", "region": "string", "invoice": { "title": "string", "taxNo": "string", "bankName": "string", "bankAccount": "string", "address": "string", "phone": "string" }, "invoiceReady": true, "poolBalance": 0, "memberCount": 0, "createdAt": "string" } } ``` **错误** - 404:`ORG_NOT_FOUND`:不存在或不归属当前 appKey --- ### `GET /v1/partner/orgs/{orgId}/members` — 已绑定员工:角色、在职状态、额度余额 鉴权:服务端签名;适用场景:员工福利购物 / 企业采购 只列经本接入方绑定的员工,含已离职的,不分页。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | orgId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].userId | string | 你自己的用户 ID(即该员工请求时的 x-open-user) | | items[].name | string | | | items[].phone | string | 接入方声明的手机号,平台不验证 | | items[].role | string | 可选值:`owner` / `admin` / `member` | | items[].status | string | 可选值:`active` / `suspended` / `offboarded` | | items[].balance | number | 员工额度余额(100 = 1 元) | | items[].boundAt | string | | **响应示例** ```json { "items": [ { "userId": "string", "name": "string", "phone": "string", "role": "owner", "status": "active", "balance": 0, "boundAt": "string" } ] } ``` **错误** - 404:`ORG_NOT_FOUND` --- ### `PUT /v1/partner/orgs/{orgId}/members/{userId}` — 把你的用户绑成员工(owner / admin / member),同时开通采购权限 鉴权:服务端签名;适用场景:员工福利购物 / 企业采购 把你的用户绑成员工,同时开通采购权限。`userId` 用你自己的用户 ID,之后该员工请求时放进 x-open-user。已是本企业在职员工时只更新角色(HTTP 200);一个用户同时只能属于一家企业。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | orgId | string | 是 | | | userId | string | 是 | 你的用户 ID,匹配 ^[\w.:@-]{1,128}$ | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | name | string | 否 | 最长 40 | | phone | string | 否 | 仅存档,平台不验证、不用于识别身份。最长 20 | | role | string | 否 | 可选值:`owner` / `admin` / `member`。默认 `"member"` | | platform | string | 否 | 可选值:`wx` / `alipay` / `pc` / `h5` / `other`。默认 `"other"` | **返回字段(已是员工,角色已更新)** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | created | boolean | 例:`false` | | member | object | | | member.userId | string | 你自己的用户 ID(即该员工请求时的 x-open-user) | | member.name | string | | | member.phone | string | 接入方声明的手机号,平台不验证 | | member.role | string | 可选值:`owner` / `admin` / `member` | | member.status | string | 可选值:`active` / `suspended` / `offboarded` | | member.balance | number | 员工额度余额(100 = 1 元) | | member.boundAt | string | | **响应示例** ```json { "ok": true, "created": false, "member": { "userId": "string", "name": "string", "phone": "string", "role": "owner", "status": "active", "balance": 0, "boundAt": "string" } } ``` **错误** - 400:`BAD_USER` / `BAD_ROLE` - 404:`ORG_NOT_FOUND` - 409:`ALREADY_BOUND`:该用户已是其他企业的在职员工 --- ### `DELETE /v1/partner/orgs/{orgId}/members/{userId}` — 员工离职:未用额度退回企业额度池,收回采购权限 鉴权:服务端签名;适用场景:员工福利购物 / 企业采购 未用额度全部退回企业额度池,收回采购权限。超级管理员(owner)不能直接离职,需先把 owner 交接给别人。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | orgId | string | 是 | | | userId | string | 是 | | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | reason | string | 否 | 最长 60 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | reclaimed | number | 退回企业的额度 | **响应示例** ```json { "ok": true, "reclaimed": 0 } ``` **错误** - 404:`ORG_NOT_FOUND` / `NOT_MEMBER` - 409:`OFFBOARD_FAILED`:成员不在职,或 owner 需先交接 ## 企业管理 以企业管理员身份调用:x-open-user 放一个被绑成 owner 或 admin 的用户。查额度池、看账单、向员工发放额度。 ### `GET /v1/enterprise/org` — 企业概览、额度池余额与流水 鉴权:用户态;适用场景:员工福利购物 / 企业采购 x-open-user 放企业管理员(owner / admin)。企业由该用户所属企业决定,请求里不接受 orgId。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | org | object | | | org.id | string | | | org.name | string | | | org.status | string | | | org.joinPolicy | string | 可选值:`auto` / `review` | | org.poolBalance | number | | | org.memberCount | integer | | | org.invoice | object | | | org.invoice.title | string | 发票抬头,缺省 = 企业名称 | | org.invoice.taxNo | string | 税号,固定等于统一社会信用代码 | | org.invoice.bankName | string | | | org.invoice.bankAccount | string | | | org.invoice.address | string | | | org.invoice.phone | string | | | org.invoiceReady | boolean | | | org.createdAt | string | | | ledger | object[] | 额度池流水,最多 100 条,新的在前 | | ledger[].kind | string | recharge / grant / revoke / expire / refund / offboard / adjust 等 | | ledger[].kindLabel | string | | | ledger[].amount | number | 带正负号 | | ledger[].balanceAfter | number | | | ledger[].remark | string | | | ledger[].createdAt | string | | | defaultExpiryDays | number | 发放额度的默认有效期(天) | | me | object | | | me.role | string | | **响应示例** ```json { "ok": true, "org": { "id": "string", "name": "string", "status": "string", "joinPolicy": "auto", "poolBalance": 0, "memberCount": 0, "invoice": { "title": "string", "taxNo": "string", "bankName": "string", "bankAccount": "string", "address": "string", "phone": "string" }, "invoiceReady": true, "createdAt": "string" }, "ledger": [ { "kind": "string", "kindLabel": "string", "amount": 0, "balanceAfter": 0, "remark": "string", "createdAt": "string" } ], "defaultExpiryDays": 0, "me": { "role": "string" } } ``` --- ### `PUT /v1/enterprise/org/profile` — 修改企业资料(名称、信用代码开户后不可改) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 企业名称与统一社会信用代码开户后不可改(传了不同的值返回 `IDENTITY_LOCKED`)。税号固定等于信用代码。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | shortName | string | 否 | | | region | string | 否 | | | contactName | string | 否 | | | adminTitle | string | 否 | | | adminEmail | string | 否 | | | licenseUrl | string | 否 | | | joinPolicy | string | 否 | 可选值:`auto` / `review` | | invoice | object | 否 | | | invoice.title | string | 否 | 发票抬头,缺省 = 企业名称 | | invoice.taxNo | string | 否 | 税号,固定等于统一社会信用代码 | | invoice.bankName | string | 否 | | | invoice.bankAccount | string | 否 | | | invoice.address | string | 否 | | | invoice.phone | string | 否 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 400:`IDENTITY_LOCKED` / `SAVE_FAILED` / `BAD_CREDIT_CODE` --- ### `GET /v1/enterprise/org/bills` — 企业账单(?id= 查看单张) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 不带 id 返回最近 36 期(按期间倒序);带 id 返回单张。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 否 | 账单 id | **返回字段(不带 id 时返回 items,带 id 时返回 bill)** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | items | object[] | | | items[].id | string | | | items[].period | string | 例:`2026-09` | | items[].granted | number | | | items[].used | number | | | items[].refunded | number | | | items[].returned | number | | | items[].serviceFee | number | | | items[].adjust | number | | | items[].adjustReason | string | | | items[].payable | number | | | items[].paid | number | | | items[].status | string | generated / confirmed / paid / closed 等 | | items[].generatedAt | string | | | items[].confirmedAt | string | | | items[].paidAt | string | | | bill | object | | | bill.id | string | | | bill.period | string | 例:`2026-09` | | bill.granted | number | | | bill.used | number | | | bill.refunded | number | | | bill.returned | number | | | bill.serviceFee | number | | | bill.adjust | number | | | bill.adjustReason | string | | | bill.payable | number | | | bill.paid | number | | | bill.status | string | generated / confirmed / paid / closed 等 | | bill.generatedAt | string | | | bill.confirmedAt | string | | | bill.paidAt | string | | **响应示例** ```json { "ok": true, "items": [ { "id": "string", "period": "2026-09", "granted": 0, "used": 0, "refunded": 0, "returned": 0, "serviceFee": 0, "adjust": 0, "adjustReason": "string", "payable": 0, "paid": 0, "status": "string", "generatedAt": "string", "confirmedAt": "string", "paidAt": "string" } ], "bill": { "id": "string", "period": "2026-09", "granted": 0, "used": 0, "refunded": 0, "returned": 0, "serviceFee": 0, "adjust": 0, "adjustReason": "string", "payable": 0, "paid": 0, "status": "string", "generatedAt": "string", "confirmedAt": "string", "paidAt": "string" } } ``` **错误** - 404:账单不存在 --- ### `POST /v1/enterprise/org/points` — 向员工发放 / 回收额度,或全员发放(100 = 1 元)。用 userId 指定员工即可 鉴权:用户态;适用场景:员工福利购物 / 企业采购 以管理员身份调用。`action`:`grant` 发放(缺省)、`revoke` 回收、`grant-all` 全员发放。grant / revoke 用 `userId`(你的用户 ID)或 `accountId` 指定员工,两者都传以 accountId 为准。 `theme` 是福利类型,可选值用 `GET /v1/enterprise/points/themes` 查,传了不认识的值返回 400。每批有效期夹到 1–90 天,到期未用完退回企业。金额单位:100 = 1 元。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`grant` / `revoke` / `grant-all`。默认 `"grant"` | | userId | string | 否 | 你的用户 ID(grant / revoke 时与 accountId 二选一) | | accountId | string | 否 | 平台内部员工账号 id | | amount | integer | 是 | 额度(100 = 1 元);grant-all 时为每人金额。≥ 1 | | theme | string | 否 | 福利类型 key。默认 `"special"` | | name | string | 否 | 这批额度的名称,如「中秋福利」 | | expiresInDays | number | 否 | 有效期(天),不传用企业默认,最终夹到 1–90 | | budgetCategory | string | 否 | 计入哪个预算类目,缺省 = theme | | lotId | string | 否 | 仅 revoke:指定从哪一批回收,不传按到期先后 | | remark | string | 否 | | **请求示例**(只含必填字段) ```json { "amount": 0 } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | replay | boolean | grant / revoke:是否为重复请求的回放 | | result | object | grant-all 时返回 | | result.granted | integer | | | result.amount | number | | | result.failed | object[] | | | result.failed[].accountId | string | | | result.failed[].message | string | | **响应示例** ```json { "ok": true, "replay": true, "result": { "granted": 0, "amount": 0, "failed": [ { "accountId": "string", "message": "string" } ] } } ``` **错误** - 400:`BAD_REQUEST`(金额或福利类型不合法、缺少员工)/ `BUDGET_EXCEEDED` / `INSUFFICIENT_POINTS`(额度池或员工余额不足,附 balance、shortfall)/ `NO_ACCOUNT` / `LOT_UNAVAILABLE` / `EMPTY` --- ### `GET /v1/enterprise/points/themes` — 福利类型列表(发放时 theme 的可选值) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 发放额度时 `theme` 的可选值,由运营在后台维护,不要写死。只返回启用中的类型。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].key | string | 例:`festival` | | items[].label | string | 例:`节日福利` | | items[].sort | integer | | **响应示例** ```json { "items": [ { "key": "festival", "label": "节日福利", "sort": 0 } ] } ``` --- ### `GET /v1/enterprise/org/dashboard` — 管理看板:员工数、额度池、本月发放与消耗 鉴权:用户态;适用场景:员工福利购物 / 企业采购 管理首页的汇总数:某个期间内的发放、使用、回池、退回与使用率。全部从额度流水按期间汇总,金额单位 100 = 1 元。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | period | string | 否 | 期间:2026 / 2026-Q3 / 2026-09;不传 = 当前年份。例:`2026-Q3` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | period | string | | | members | integer | 在职员工数 | | poolBalance | number | 企业额度池当前余额 | | granted | number | 期间内发放(含任务奖励) | | used | number | 期间内下单使用 | | returned | number | 回池:回收 + 过期 + 离职 + 兑换扣回 | | refunded | number | 取消 / 退款退回员工 | | usageRate | number | 使用率(%),一位小数:(used − refunded) / granted | | perCapita | number | 人均发放 | | covered | integer | 期间内被发放过额度的人数 | | redemptions | integer | 期间内下单笔数 | **响应示例** ```json { "ok": true, "period": "string", "members": 0, "poolBalance": 0, "granted": 0, "used": 0, "returned": 0, "refunded": 0, "usageRate": 0, "perCapita": 0, "covered": 0, "redemptions": 0 } ``` **错误** - 400:操作失败,`message` 说明原因(部分情况不带 code) --- ### `GET /v1/enterprise/org/members` — 员工列表(含各自额度余额) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 本企业员工及各自余额,含已停用、已离职的(看 status),不分页。只列在你这个接入方所属产品下的员工。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | items | object[] | | | items[].id | string | 成员记录 id | | items[].orgId | string | | | items[].accountId | string | 员工的平台账号 id;单个员工接口的路径参数 | | items[].role | string | 可选值:`owner` / `admin` / `member` | | items[].status | string | 可选值:`active` / `suspended` / `offboarded` | | items[].realName | string | | | items[].nickname | string | | | items[].phone | string | | | items[].birthday | string | | | items[].departmentId | string | | | items[].balance | number | 员工额度余额(100 = 1 元) | | items[].createdAt | string | | **响应示例** ```json { "ok": true, "items": [ { "id": "string", "orgId": "string", "accountId": "string", "role": "owner", "status": "active", "realName": "string", "nickname": "string", "phone": "string", "birthday": "string", "departmentId": "string", "balance": 0, "createdAt": "string" } ] } ``` --- ### `GET/PUT /v1/enterprise/org/members/{userId}` — 员工详情 / 修改资料(带 ?by=userId 时路径里放你的用户 ID) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 #### GET:员工额度明细 员工手上还有余量的额度批次,以及离职时的回收记录。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | accountId | string | 是 | 员工的平台账号 id;带 `?by=userId` 时为你的用户 ID | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | by | string | 否 | 传 userId 时,路径里放你自己的用户 ID。可选值:`userId` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | lots | object[] | | | lots[].id | string | | | lots[].name | string | | | lots[].theme | string | | | lots[].themeLabel | string | | | lots[].amount | number | 发放额度 | | lots[].remaining | number | 剩余额度 | | lots[].grantedAt | string | | | lots[].expiresAt | string | 可能为 null | | offboardRecord | object[] | | | offboardRecord[].lotId | string | | | offboardRecord[].name | string | | | offboardRecord[].amount | number | | | offboardRecord[].at | string | | **响应示例** ```json { "ok": true, "lots": [ { "id": "string", "name": "string", "theme": "string", "themeLabel": "string", "amount": 0, "remaining": 0, "grantedAt": "string", "expiresAt": "string" } ], "offboardRecord": [ { "lotId": "string", "name": "string", "amount": 0, "at": "string" } ] } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### PUT:修改员工资料 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | accountId | string | 是 | 员工的平台账号 id;带 `?by=userId` 时为你的用户 ID | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | by | string | 否 | 传 userId 时,路径里放你自己的用户 ID。可选值:`userId` | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | realName | string | 否 | | | departmentId | string | 否 | null 或空串 = 清空部门。可能为 null | | birthday | string | 否 | YYYY-MM-DD 或 MM-DD | | gender | string | 否 | 可选值:`male` / `female` / `` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 400:操作失败,`message` 说明原因(部分情况不带 code) - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `POST /v1/enterprise/org/members/{userId}` — 停用 / 恢复员工(带 ?by=userId 时路径里放你的用户 ID) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 `suspend` 停用(额度保留,可恢复)· `reactivate` 恢复 · `offboard` 离职(未用额度退回企业)· `set-role` 改角色(`role` 为 admin 或 member)。不能对自己操作;owner 不能直接停用或离职,需先交接。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | accountId | string | 是 | 员工的平台账号 id;带 `?by=userId` 时为你的用户 ID | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | by | string | 否 | 传 userId 时,路径里放你自己的用户 ID。可选值:`userId` | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 是 | 可选值:`suspend` / `reactivate` / `offboard` / `set-role` | | reason | string | 否 | offboard 时可填 | | role | string | 否 | set-role 时必填。可选值:`admin` / `member` | **请求示例**(只含必填字段) ```json { "action": "suspend" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | role | string | set-role 时返回 | | result | object | offboard 时返回 | | result.lots | integer | | | result.amount | number | | | result.legacy | number | | **响应示例** ```json { "ok": true, "role": "string", "result": { "lots": 0, "amount": 0, "legacy": 0 } } ``` **错误** - 400:`SELF` 不能对自己操作 / `OWNER_LOCKED` / `LAST_MANAGER` / `NOT_FOUND`,或 message 说明的状态不允许 - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `GET/PATCH /v1/enterprise/org/points-settings` — 签到规则、发放默认有效期等企业级设置 鉴权:用户态;适用场景:员工福利购物 / 企业采购 #### GET:企业额度设置 `effective` 生效值;`overrides` 企业自己设过的项(null = 跟随平台);`platform` 平台默认。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | effective | object | | | effective.checkinEnabled | boolean | | | effective.checkinDailyAmount | number | | | effective.checkinStreakDays | number | | | effective.checkinStreakBonus | number | | | effective.pointsExpiryDays | number | 发放默认有效期(天),1–90 | | overrides | object | | | overrides.checkinEnabled | boolean | | | overrides.checkinDailyAmount | number | | | overrides.checkinStreakDays | number | | | overrides.checkinStreakBonus | number | | | overrides.pointsExpiryDays | number | 发放默认有效期(天),1–90 | | platform | object | | | platform.checkinEnabled | boolean | | | platform.checkinDailyAmount | number | | | platform.checkinStreakDays | number | | | platform.checkinStreakBonus | number | | | platform.pointsExpiryDays | number | 发放默认有效期(天),1–90 | **响应示例** ```json { "ok": true, "effective": { "checkinEnabled": true, "checkinDailyAmount": 0, "checkinStreakDays": 0, "checkinStreakBonus": 0, "pointsExpiryDays": 0 }, "overrides": { "checkinEnabled": true, "checkinDailyAmount": 0, "checkinStreakDays": 0, "checkinStreakBonus": 0, "pointsExpiryDays": 0 }, "platform": { "checkinEnabled": true, "checkinDailyAmount": 0, "checkinStreakDays": 0, "checkinStreakBonus": 0, "pointsExpiryDays": 0 } } ``` #### PATCH:修改企业额度设置 **请求体(application/json,只传要改的项;显式传 null = 退回跟随平台默认)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | checkinEnabled | boolean | 否 | 可能为 null | | checkinDailyAmount | number | 否 | ≥ 1,≤ 10000。可能为 null | | checkinStreakDays | number | 否 | ≥ 2,≤ 60。可能为 null | | checkinStreakBonus | number | 否 | ≥ 0,≤ 100000。可能为 null | | pointsExpiryDays | number | 否 | ≥ 1,≤ 90。可能为 null | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | effective | object | | | effective.checkinEnabled | boolean | | | effective.checkinDailyAmount | number | | | effective.checkinStreakDays | number | | | effective.checkinStreakBonus | number | | | effective.pointsExpiryDays | number | 发放默认有效期(天),1–90 | | overrides | object | | | overrides.checkinEnabled | boolean | | | overrides.checkinDailyAmount | number | | | overrides.checkinStreakDays | number | | | overrides.checkinStreakBonus | number | | | overrides.pointsExpiryDays | number | 发放默认有效期(天),1–90 | | platform | object | | | platform.checkinEnabled | boolean | | | platform.checkinDailyAmount | number | | | platform.checkinStreakDays | number | | | platform.checkinStreakBonus | number | | | platform.pointsExpiryDays | number | 发放默认有效期(天),1–90 | **响应示例** ```json { "ok": true, "effective": { "checkinEnabled": true, "checkinDailyAmount": 0, "checkinStreakDays": 0, "checkinStreakBonus": 0, "pointsExpiryDays": 0 }, "overrides": { "checkinEnabled": true, "checkinDailyAmount": 0, "checkinStreakDays": 0, "checkinStreakBonus": 0, "pointsExpiryDays": 0 }, "platform": { "checkinEnabled": true, "checkinDailyAmount": 0, "checkinStreakDays": 0, "checkinStreakBonus": 0, "pointsExpiryDays": 0 } } ``` **错误** - 400:参数不合法 --- ### `GET /v1/enterprise/org/consumption` — 员工消耗记录与汇总(按人、时间筛选) 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 可选。全体员工的消耗侧流水:下单扣减,以及取消、退款、建单失败的退回(用 `direction` 区分)。`summary` 跟随当前筛选条件,不是全量。新的在前。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | accountId | string | 否 | 只看某个员工(平台账号 id) | | from | string(date) | 否 | 起始日期 YYYY-MM-DD(含) | | to | string(date) | 否 | 截止日期 YYYY-MM-DD(含) | | kind | string | 否 | 只看某一类;不传 = 四类都要。可选值:`order` / `order_cancel` / `refund` / `order_rollback` | | page | integer | 否 | 默认 `1`。≥ 1 | | pageSize | integer | 否 | 上限 1000,供导出分批拉取。默认 `20`。≥ 1,≤ 1000 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | total | integer | | | page | integer | | | pageSize | integer | | | summary | object | | | summary.spent | number | 下单扣减合计 | | summary.refunded | number | 各种退回合计 | | summary.net | number | 净消耗 = spent − refunded,不小于 0 | | summary.people | integer | 有消耗的人数 | | summary.orders | integer | 下单笔数 | | items | object[] | | | items[].accountId | string | | | items[].name | string | 姓名,没有则昵称或手机号 | | items[].phone | string | | | items[].departmentName | string | | | items[].kind | string | 可选值:`order` / `order_cancel` / `refund` / `order_rollback` | | items[].kindLabel | string | | | items[].amount | number | 恒为正数,方向看 direction | | items[].direction | string | 可选值:`out` / `in` | | items[].outOrderId | string | | | items[].bizOrderId | string | 订单还没建成时为空 | | items[].orderStatus | integer | | | items[].remark | string | | | items[].createdAt | string | | **响应示例** ```json { "ok": true, "total": 0, "page": 0, "pageSize": 0, "summary": { "spent": 0, "refunded": 0, "net": 0, "people": 0, "orders": 0 }, "items": [ { "accountId": "string", "name": "string", "phone": "string", "departmentName": "string", "kind": "order", "kindLabel": "string", "amount": 0, "direction": "out", "outOrderId": "string", "bizOrderId": "string", "orderStatus": 0, "remark": "string", "createdAt": "string" } ] } ``` --- ### `GET /v1/enterprise/org/birthdays` — 近期生日员工(?range=today|week|month),发生日福利用 鉴权:用户态(可选接口);适用场景:员工福利购物 可选。按月日匹配(不看年份)列出近期过生日的员工;`?missing=1` 改为返回还没登记生日的员工名单。生日用「修改员工资料」接口登记。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | range | string | 否 | 可选值:`today` / `week` / `month`。默认 `"today"` | | missing | string | 否 | 传 1 返回缺生日名单(此时忽略 range,响应不带 range)。可选值:`1` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | range | string | | | items | object[] | | | items[].accountId | string | | | items[].name | string | | | items[].phone | string | | | items[].birthday | string | 缺生日名单不带 | | items[].daysUntil | integer | 距生日还有几天,今天为 0;缺生日名单不带 | **响应示例** ```json { "ok": true, "range": "string", "items": [ { "accountId": "string", "name": "string", "phone": "string", "birthday": "string", "daysUntil": 0 } ] } ``` --- ### `GET/POST/PUT/DELETE /v1/enterprise/org/departments` — 部门管理 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 #### GET:部门列表 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | items | object[] | | | items[].id | string | | | items[].name | string | | | items[].sort | number | | | items[].memberCount | integer | | | items[].createdAt | string | | **响应示例** ```json { "ok": true, "items": [ { "id": "string", "name": "string", "sort": 0, "memberCount": 0, "createdAt": "string" } ] } ``` #### POST:新建部门 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | name | string | 是 | | | sort | number | 否 | 默认 `0` | **请求示例**(只含必填字段) ```json { "name": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | id | string | | **响应示例** ```json { "ok": true, "id": "string" } ``` **错误** - 400:操作失败,`message` 说明原因(部分情况不带 code) #### PUT:修改部门 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | | name | string | 否 | | | sort | number | 否 | | **请求示例**(只含必填字段) ```json { "id": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### DELETE:删除部门 部门下还有员工时不能删。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | 部门 id | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 400:操作失败,`message` 说明原因(部分情况不带 code) --- ### `GET/POST/DELETE /v1/enterprise/org/budgets` — 部门预算 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 #### GET:预算列表 / 预算看板 带 `dashboard=<期间>` 返回该期间的预算执行看板(lines + totals);否则返回预算列表,可用 `period` 筛选。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | period | string | 否 | 如 2026 / 2026-Q3 / 2026-09 | | dashboard | string | 否 | 看板期间,格式同 period | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | items | object[] | | | items[].id | string | | | items[].periodKind | string | 可选值:`year` / `quarter` / `month` | | items[].period | string | | | items[].category | string | | | items[].departmentId | string | | | items[].amount | number | | | items[].alertPct | integer | | | items[].overspendPolicy | string | 可选值:`allow` / `block` | | period | string | | | lines | object[] | | | lines[].id | string | | | lines[].periodKind | string | 可选值:`year` / `quarter` / `month` | | lines[].period | string | | | lines[].category | string | | | lines[].departmentId | string | | | lines[].amount | number | | | lines[].alertPct | integer | | | lines[].overspendPolicy | string | 可选值:`allow` / `block` | | lines[].granted | number | | | lines[].used | number | | | lines[].remaining | number | | | lines[].ratePct | number | | | lines[].alert | string | 可选值:`none` / `warn` / `over` | | totals | object | | | totals.amount | number | | | totals.granted | number | | | totals.used | number | | **响应示例** ```json { "ok": true, "items": [ { "id": "string", "periodKind": "year", "period": "string", "category": "string", "departmentId": "string", "amount": 0, "alertPct": 0, "overspendPolicy": "allow" } ], "period": "string", "lines": [ { "id": "string", "periodKind": "year", "period": "string", "category": "string", "departmentId": "string", "amount": 0, "alertPct": 0, "overspendPolicy": "allow", "granted": 0, "used": 0, "remaining": 0, "ratePct": 0, "alert": "none" } ], "totals": { "amount": 0, "granted": 0, "used": 0 } } ``` **错误** - 400:操作失败,`message` 说明原因(部分情况不带 code) #### POST:设置预算 按 期间 + 类目 + 部门 新建或覆盖。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | period | string | 是 | 2026 / 2026-Q3 / 2026-09 | | category | string | 否 | 福利类型 key;空 = 不分类目 | | departmentId | string | 否 | 空 = 不分部门 | | amount | integer | 是 | ≥ 0 | | alertPct | integer | 否 | 默认 `80`。≥ 1,≤ 100 | | overspendPolicy | string | 否 | 可选值:`allow` / `block`。默认 `"allow"` | **请求示例**(只含必填字段) ```json { "period": "string", "amount": 0 } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | id | string | | **响应示例** ```json { "ok": true, "id": "string" } ``` **错误** - 400:操作失败,`message` 说明原因(部分情况不带 code) #### DELETE:删除预算 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | 预算 id | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 ## 员工额度 以员工身份调用:查余额、流水与每批额度的到期时间,结算前判断能否用企业额度支付。 ### `GET/PUT /v1/buyer/me` — 当前用户资料与所属企业(org:企业 id、名称、状态、本人角色、余额;没有归属为 null) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 #### GET:用户资料 首次访问自动建档。`org` 是当前用户所属的企业:id、名称、在本产品里的开通状态(active 才能交易)、本人角色(owner / admin / member)、额度余额;没有归属企业为 null。登录后调一次即可拿全身份,按 role 决定显不显示企业管理入口。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | account | object | | | account.id | string | | | account.platform | string | 可选值:`wx` / `alipay` / `pc` / `h5` / `other` | | account.externalId | string | = x-open-user | | account.nickname | string | | | account.avatar | string | | | account.realName | string | 未填为空串 | | account.birthday | string | 未填为空串 | | account.gender | string | 未填为空串 | | account.createdAt | string | | | account.lastSeenAt | string | | | org | object | 所属企业;没有为 null。可能为 null | | org.id | string | 企业 id(orgId) | | org.name | string | | | org.status | string | 企业在本产品里的状态:active 才能交易;pending 待激活 / 开通审核中,rejected、disabled、none | | org.role | string | 可选值:`owner` / `admin` / `member` | | org.balance | integer | 本人额度余额(100 = 1 元) | **响应示例** ```json { "account": { "id": "string", "platform": "wx", "externalId": "string", "nickname": "string", "avatar": "string", "realName": "string", "birthday": "string", "gender": "string", "createdAt": "string", "lastSeenAt": "string" }, "org": { "id": "string", "name": "string", "status": "string", "role": "owner", "balance": 0 } } ``` #### PUT:修改用户资料 不接受 phone。传空串清空对应字段。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | nickname | string | 否 | | | avatar | string | 否 | | | realName | string | 否 | | | birthday | string | 否 | YYYY-MM-DD 或 MM-DD,须为过去的日期 | | gender | string | 否 | 可选值:`male` / `female` / `` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | account | object | | **响应示例** ```json { "ok": true, "account": null } ``` **错误** - 400:`BAD_BIRTHDAY` / `BAD_GENDER` --- ### `GET /v1/enterprise/points` — 结算页判断:这单能否用企业额度支付、余额多少 鉴权:用户态;适用场景:员工福利购物 / 企业采购 结算页用:这个员工能不能用企业额度、余额多少。未绑定企业时 `bound: false`。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bound | boolean | | | canUsePoints | boolean | 企业为 active 时为 true | | balance | number | | | org | object | | | org.name | string | | | org.status | string | | | role | string | | **响应示例** ```json { "bound": true, "canUsePoints": true, "balance": 0, "org": { "name": "string", "status": "string" }, "role": "string" } ``` --- ### `GET /v1/enterprise/points/summary` — 额度总览:余额、即将到期、所属企业与角色 鉴权:用户态;适用场景:员工福利购物 / 企业采购 余额、30 天内即将到期的额度、所属企业与角色。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bound | boolean | | | balance | number | | | expiringSoon | object | | | expiringSoon.amount | number | | | expiringSoon.nearestDate | string | | | org | object | | | org.name | string | | | org.status | string | | | org.role | string | | | canUsePoints | boolean | | | ratio | integer | 100 = 1 元。例:`100` | **响应示例** ```json { "bound": true, "balance": 0, "expiringSoon": { "amount": 0, "nearestDate": "string" }, "org": { "name": "string", "status": "string", "role": "string" }, "canUsePoints": true, "ratio": 100 } ``` --- ### `GET /v1/enterprise/points/ledger` — 额度流水(发放 / 下单 / 退回 / 过期) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 最多取最近 200 条再分页,因此 total 最大 200。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | type | string | 否 | 不传 = 全部;refund 包含各种退回。可选值:`grant` / `order` / `refund` / `expire` | | page | integer | 否 | 默认 `1`。≥ 1 | | pageSize | integer | 否 | 默认 `20`。≥ 1,≤ 100 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bound | boolean | | | total | integer | | | page | integer | | | pageSize | integer | | | items | object[] | | | items[].kind | string | | | items[].label | string | 展示用文案,由服务端下发 | | items[].amount | number | 带正负号 | | items[].balanceAfter | number | | | items[].remark | string | 可能为 null | | items[].lots | object[] | | | items[].lots[].id | string | | | items[].lots[].name | string | | | items[].lots[].theme | string | | | items[].createdAt | string | | **响应示例** ```json { "bound": true, "total": 0, "page": 0, "pageSize": 0, "items": [ { "kind": "string", "label": "string", "amount": 0, "balanceAfter": 0, "remark": "string", "lots": [ {} ], "createdAt": "string" } ] } ``` --- ### `GET /v1/enterprise/points/welfares` — 按发放批次查看剩余额度与到期日 鉴权:用户态;适用场景:员工福利购物 / 企业采购 只含还有余量的批次,按到期日升序。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | theme | string | 否 | 福利类型 key | | expiringWithin | integer | 否 | 只看 N 天内到期的。≥ 1 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bound | boolean | | | items | object[] | | | items[].id | string | | | items[].name | string | | | items[].theme | string | | | items[].themeLabel | string | | | items[].amount | number | 发放额度 | | items[].remaining | number | 剩余额度 | | items[].grantedAt | string | | | items[].expiresAt | string | 可能为 null | | total | number | 所有批次剩余之和 | | expiringAmount | number | 有到期日的批次剩余之和 | **响应示例** ```json { "bound": true, "items": [ { "id": "string", "name": "string", "theme": "string", "themeLabel": "string", "amount": 0, "remaining": 0, "grantedAt": "string", "expiresAt": "string" } ], "total": 0, "expiringAmount": 0 } ``` --- ### `GET /v1/enterprise/points/rules` — 额度使用规则文案(登录前可看) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 登录前也能看;带 x-open-user 时有效期按该员工所属企业的设置显示。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ratio | integer | 例:`100` | | expiryPolicy | object | | | expiryPolicy.defaultDays | number | | | expiryPolicy.onExpire | string | 例:`return_to_org` | | sections | object[] | | | sections[].title | string | | | sections[].body | string | | **响应示例** ```json { "ratio": 100, "expiryPolicy": { "defaultDays": 0, "onExpire": "return_to_org" }, "sections": [ { "title": "string", "body": "string" } ] } ``` --- ### `GET/POST /v1/enterprise/points/checkin` — 每日签到:GET 看今天能否领与连续天数,POST 领取(幂等) 鉴权:用户态(可选接口);适用场景:员工福利购物 #### GET:签到状态 可选。今天能不能领、连续几个工作日、每日金额与连签奖励(画签到卡用)。金额与阈值由服务端下发、企业可调,不要写死。未绑定企业时只返回 `{ bound: false }`。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bound | boolean | | | enabled | boolean | 企业是否开启签到 | | canClaim | boolean | | | reason | string | 不能领的原因。可选值:`disabled` / `weekend` / `claimed` | | streak | integer | 连续工作日数(今天未签时为签了之后的天数) | | today | string | 例:`2026-10-20` | | isWeekend | boolean | | | dailyAmount | number | | | streakDays | number | 连签几天发奖励 | | streakBonus | number | | | claimedDays | string[] | 最近已签的日期 | **响应示例** ```json { "bound": true, "enabled": true, "canClaim": true, "reason": "disabled", "streak": 0, "today": "2026-10-20", "isWeekend": true, "dailyAmount": 0, "streakDays": 0, "streakBonus": 0, "claimedDays": [ "string" ] } ``` #### POST:签到领额度 可选。**幂等**:同一天重复调只发一次。周末不签到。额度从员工所属企业的额度池划出。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | amount | number | 本次发放(含奖励) | | bonus | number | 其中连签奖励 | | streak | integer | | | balance | number | 领取后余额 | | replay | boolean | | **响应示例** ```json { "ok": true, "amount": 0, "bonus": 0, "streak": 0, "balance": 0, "replay": true } ``` **错误** - 400:`NOT_BOUND` 未绑定企业 / `DISABLED` 企业未开启签到 / `WEEKEND` 周末 / `CLAIMED` 今天已领 / `GRANT_FAILED` --- ### `GET/POST /v1/enterprise/notifications` — 站内信:GET 列表(?unread=1),POST 标已读 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 #### GET:站内信列表 可选。发给当前用户的站内信(如预算预警、任务变更),新的在前,最多 50 条。只存表,不推送。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | unread | string | 否 | 传 1 只看未读。可选值:`1` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | unread | integer | 未读总数 | | items | object[] | | | items[].id | string | | | items[].kind | string | | | items[].title | string | | | items[].body | string | | | items[].refId | string | 关联对象 id(如任务 id) | | items[].readAt | string | 未读时不返回 | | items[].createdAt | string | | **响应示例** ```json { "ok": true, "unread": 0, "items": [ { "id": "string", "kind": "string", "title": "string", "body": "string", "refId": "string", "readAt": "string", "createdAt": "string" } ] } ``` #### POST:标记已读 可选。不传 ids = 全部标为已读。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | ids | string[] | 否 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | marked | integer | 本次标记的条数 | **响应示例** ```json { "ok": true, "marked": 0 } ``` ## 福豆任务 管理员发布任务(奖励型:员工完成后得额度;兑换型:员工用额度兑福利),员工报名、提交凭证、兑换,管理员审核与核销。奖励型发布时从企业额度池冻结预算。全部可选,做员工激励时再接。 ### `GET/POST /v1/enterprise/org/tasks` — 管理员:任务列表与概览(?filter=)/ 发布任务(带 idempotencyKey) 鉴权:用户态(可选接口);适用场景:员工福利购物 #### GET:任务列表与概览 可选。新建的在前,每页 20 条。`overview` 是顶部概览(进行中 / 待审核 / 待核销 / 已结束)。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | filter | string | 否 | 可选值:`all` / `reward` / `consume` / `reviewing`。默认 `"all"` | | cursor | string | 否 | 翻页游标:取上一页返回的 nextCursor,首页不传 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | overview | object | | | overview.ongoing | integer | | | overview.pendingReview | integer | | | overview.pendingWriteoff | integer | | | overview.ended | integer | | | items | object[] | | | items[].id | string | | | items[].title | string | | | items[].category | string | | | items[].categoryLabel | string | | | items[].description | string | | | items[].coverUrl | string | 可能为 null | | items[].settleMode | string | 可选值:`reward` / `consume` | | items[].points | number | 每人奖励或消耗的额度(100 = 1 元) | | items[].quota | integer | null = 不限。可能为 null | | items[].remaining | integer | 可能为 null | | items[].startAt | string | | | items[].endAt | string | | | items[].phase | string | 可选值:`not_started` / `ongoing` / `ended` | | items[].needSignup | boolean | | | items[].signupFull | boolean | | | items[].completeMode | string | 可选值:`direct` / `submit` | | items[].reviewMode | string | 可选值:`auto` / `manual` | | items[].needWriteoff | boolean | | | items[].scopeText | string | 如「全体员工」「财务部、仓储部」 | | items[].submitSchema | object[] | | | items[].submitSchema[].key | string | | | items[].submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | items[].submitSchema[].label | string | 最长 20 | | items[].submitSchema[].required | boolean | | | items[].submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | items[].pickupInfo | object | 消耗型任务的领取信息 | | items[].pickupInfo.location | string | | | items[].pickupInfo.timeText | string | | | items[].pickupInfo.startAt | string | | | items[].pickupInfo.endAt | string | | | items[].pickupInfo.rules | string | | | items[].status | string | 可选值:`active` / `ended` / `cancelled` | | items[].scopeKind | string | 可选值:`all` / `departments` / `members` | | items[].scopeIds | string[] | | | items[].signupQuota | integer | 可能为 null | | items[].budgetFrozen | number | 已冻结的预算 | | items[].stats | object | | | items[].stats.signedUp | integer | | | items[].stats.joined | integer | | | items[].stats.completed | integer | | | items[].stats.redeemed | integer | | | items[].stats.pendingReview | integer | | | items[].stats.pendingWriteoff | integer | | | items[].version | integer | 编辑时作为 expectedVersion 带回 | | items[].editRules | object | 前端据此置灰,服务端照样校验 | | items[].editRules.locked | string[] | 当前不可改的字段名 | | items[].editRules.minQuota | integer | | | items[].editRules.pointsEditable | boolean | | | items[].editRules.startAtEditable | boolean | | | items[].editRules.minSignupQuota | integer | | | nextCursor | string | 下一页游标;null = 没有下一页。可能为 null | **响应示例** ```json { "overview": { "ongoing": 0, "pendingReview": 0, "pendingWriteoff": 0, "ended": 0 }, "items": [ { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [ {} ], "pickupInfo": { "location": "string", "timeText": "string", "startAt": "string", "endAt": "string", "rules": "string" }, "status": "active", "scopeKind": "all", "scopeIds": [ "string" ], "signupQuota": 0, "budgetFrozen": 0, "stats": { "signedUp": 0, "joined": 0, "completed": 0, "redeemed": 0, "pendingReview": 0, "pendingWriteoff": 0 }, "version": 0, "editRules": { "locked": [], "minQuota": 0, "pointsEditable": true, "startAtEditable": true, "minSignupQuota": 0 } } ], "nextCursor": "string" } ``` #### POST:发布任务 可选。奖励型在同一事务里从企业额度池冻结预算(每人额度 × 名额,不限名额时按范围人数),额度池不够返回 `POOL_INSUFFICIENT`、任务不建;任务结束时未用完的退回额度池。复制任务 = 拿详情预填后再发布。建议传 `idempotencyKey`。 **请求体(application/json,发布与编辑任务的字段。消耗型恒为直接完成、自动审核;只有消耗型有核销与领取信息。)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | title | string | 是 | 最长 30 | | description | string | 否 | 最长 500 | | coverUrl | string | 是 | 封面图 http(s) 地址,发布时必填;用「上传任务封面」拿到 | | category | string | 否 | 奖励型可选 training / learning / survey / activity / other;消耗型可选 festival / daily / activity / other。可选值:`training` / `learning` / `survey` / `activity` / `festival` / `daily` / `other` | | settleMode | string | 是 | reward 奖励额度(员工做任务赚)· consume 消耗额度(员工用额度兑换)。可选值:`reward` / `consume` | | points | integer | 是 | 每人奖励或消耗的额度(100 = 1 元)。≥ 1,≤ 10000000 | | quota | integer | 否 | 名额;不传 = 不限。≥ 1,≤ 100000。可能为 null | | scopeKind | string | 否 | 可选值:`all` / `departments` / `members`。默认 `"all"` | | scopeIds | string[] | 否 | 部门 id 或员工平台账号 id(scopeKind 非 all 时必填) | | startAt | string | 否 | 不传 = 立即开始 | | endAt | string | 是 | 截止时间,必填,须晚于开始时间与现在 | | needSignup | boolean | 否 | | | signupQuota | integer | 否 | ≥ 1。可能为 null | | completeMode | string | 否 | 仅奖励型:直接完成 / 提交结果。可选值:`direct` / `submit`。默认 `"direct"` | | reviewMode | string | 否 | 仅奖励型 + submit:缺省 manual 人工审核。可选值:`auto` / `manual` | | submitSchema | object[] | 否 | completeMode = submit 时必填。最多 10 项 | | submitSchema[].key | string | 是 | | | submitSchema[].type | string | 是 | 可选值:`text` / `image` / `file` / `link` | | submitSchema[].label | string | 是 | 最长 20 | | submitSchema[].required | boolean | 否 | | | submitSchema[].max | integer | 否 | text 字数 / link 长度 / image、file 个数(≤9)上限 | | needWriteoff | boolean | 否 | 仅消耗型:兑换后是否需要线下核销(发领取码) | | pickupInfo | object | 否 | 消耗型任务的领取信息 | | pickupInfo.location | string | 否 | | | pickupInfo.timeText | string | 否 | | | pickupInfo.startAt | string | 否 | | | pickupInfo.endAt | string | 否 | | | pickupInfo.rules | string | 否 | | | idempotencyKey | string | 否 | 最长 128 | **请求示例**(只含必填字段) ```json { "title": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "endAt": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | task | object | 管理视角的任务 | | task.id | string | | | task.title | string | | | task.category | string | | | task.categoryLabel | string | | | task.description | string | | | task.coverUrl | string | 可能为 null | | task.settleMode | string | 可选值:`reward` / `consume` | | task.points | number | 每人奖励或消耗的额度(100 = 1 元) | | task.quota | integer | null = 不限。可能为 null | | task.remaining | integer | 可能为 null | | task.startAt | string | | | task.endAt | string | | | task.phase | string | 可选值:`not_started` / `ongoing` / `ended` | | task.needSignup | boolean | | | task.signupFull | boolean | | | task.completeMode | string | 可选值:`direct` / `submit` | | task.reviewMode | string | 可选值:`auto` / `manual` | | task.needWriteoff | boolean | | | task.scopeText | string | 如「全体员工」「财务部、仓储部」 | | task.submitSchema | object[] | | | task.submitSchema[].key | string | | | task.submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | task.submitSchema[].label | string | 最长 20 | | task.submitSchema[].required | boolean | | | task.submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | task.pickupInfo | object | 消耗型任务的领取信息 | | task.pickupInfo.location | string | | | task.pickupInfo.timeText | string | | | task.pickupInfo.startAt | string | | | task.pickupInfo.endAt | string | | | task.pickupInfo.rules | string | | | task.status | string | 可选值:`active` / `ended` / `cancelled` | | task.scopeKind | string | 可选值:`all` / `departments` / `members` | | task.scopeIds | string[] | | | task.signupQuota | integer | 可能为 null | | task.budgetFrozen | number | 已冻结的预算 | | task.stats | object | | | task.stats.signedUp | integer | | | task.stats.joined | integer | | | task.stats.completed | integer | | | task.stats.redeemed | integer | | | task.stats.pendingReview | integer | | | task.stats.pendingWriteoff | integer | | | task.version | integer | 编辑时作为 expectedVersion 带回 | | task.editRules | object | 前端据此置灰,服务端照样校验 | | task.editRules.locked | string[] | 当前不可改的字段名 | | task.editRules.minQuota | integer | | | task.editRules.pointsEditable | boolean | | | task.editRules.startAtEditable | boolean | | | task.editRules.minSignupQuota | integer | | | poolBalance | number | 发布后的企业额度池余额 | | budgetWarn | string | 超出预算预警线时的提示文案。可能为 null | **响应示例** ```json { "task": { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [ { "key": "string", "type": "text", "label": "string", "required": true, "max": 0 } ], "pickupInfo": { "location": "string", "timeText": "string", "startAt": "string", "endAt": "string", "rules": "string" }, "status": "active", "scopeKind": "all", "scopeIds": [ "string" ], "signupQuota": 0, "budgetFrozen": 0, "stats": { "signedUp": 0, "joined": 0, "completed": 0, "redeemed": 0, "pendingReview": 0, "pendingWriteoff": 0 }, "version": 0, "editRules": { "locked": [ "string" ], "minQuota": 0, "pointsEditable": true, "startAtEditable": true, "minSignupQuota": 0 } }, "poolBalance": 0, "budgetWarn": "string" } ``` **错误** - 400:`BAD_REQUEST`(message 说明哪一项不合法)/ `POOL_INSUFFICIENT` 企业额度池不足 --- ### `GET /v1/enterprise/org/tasks/budget-preview` — 管理员:发布前试算预计最高支出与额度池余额 鉴权:用户态(可选接口);适用场景:员工福利购物 可选。发布页底部的「预计最高支出 / 额度池余额」,与发布同一套算法。编辑时带 `taskId`(结算方式取任务本身),另返回 `delta`:本次修改需追加(正)或释放(负)的额度。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | settleMode | string | 否 | 可选值:`reward` / `consume`。默认 `"reward"` | | points | integer | 否 | 每人额度 | | quota | integer | 否 | 名额;不传 = 不限 | | scopeKind | string | 否 | 可选值:`all` / `departments` / `members`。默认 `"all"` | | scopeIds | string | 否 | 逗号分隔 | | taskId | string | 否 | 编辑预览时传 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | maxSpend | number | 预计最高支出;消耗型为 0 | | cap | integer | 按名额与范围人数算出的最多发放人数 | | poolBalance | number | | | budgetWarn | string | 可能为 null | | delta | number | 仅带 taskId 时返回 | **响应示例** ```json { "maxSpend": 0, "cap": 0, "poolBalance": 0, "budgetWarn": "string", "delta": 0 } ``` **错误** - 400:`BAD_REQUEST` - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 --- ### `GET/POST /v1/enterprise/org/tasks/{taskId}` — 管理员:任务详情与参与人 / 编辑、提前结束 鉴权:用户态(可选接口);适用场景:员工福利购物 #### GET:任务详情与参与人 可选。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | taskId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | task | object | 管理视角的任务 | | task.id | string | | | task.title | string | | | task.category | string | | | task.categoryLabel | string | | | task.description | string | | | task.coverUrl | string | 可能为 null | | task.settleMode | string | 可选值:`reward` / `consume` | | task.points | number | 每人奖励或消耗的额度(100 = 1 元) | | task.quota | integer | null = 不限。可能为 null | | task.remaining | integer | 可能为 null | | task.startAt | string | | | task.endAt | string | | | task.phase | string | 可选值:`not_started` / `ongoing` / `ended` | | task.needSignup | boolean | | | task.signupFull | boolean | | | task.completeMode | string | 可选值:`direct` / `submit` | | task.reviewMode | string | 可选值:`auto` / `manual` | | task.needWriteoff | boolean | | | task.scopeText | string | 如「全体员工」「财务部、仓储部」 | | task.submitSchema | object[] | | | task.submitSchema[].key | string | | | task.submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | task.submitSchema[].label | string | 最长 20 | | task.submitSchema[].required | boolean | | | task.submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | task.pickupInfo | object | 消耗型任务的领取信息 | | task.pickupInfo.location | string | | | task.pickupInfo.timeText | string | | | task.pickupInfo.startAt | string | | | task.pickupInfo.endAt | string | | | task.pickupInfo.rules | string | | | task.status | string | 可选值:`active` / `ended` / `cancelled` | | task.scopeKind | string | 可选值:`all` / `departments` / `members` | | task.scopeIds | string[] | | | task.signupQuota | integer | 可能为 null | | task.budgetFrozen | number | 已冻结的预算 | | task.stats | object | | | task.stats.signedUp | integer | | | task.stats.joined | integer | | | task.stats.completed | integer | | | task.stats.redeemed | integer | | | task.stats.pendingReview | integer | | | task.stats.pendingWriteoff | integer | | | task.version | integer | 编辑时作为 expectedVersion 带回 | | task.editRules | object | 前端据此置灰,服务端照样校验 | | task.editRules.locked | string[] | 当前不可改的字段名 | | task.editRules.minQuota | integer | | | task.editRules.pointsEditable | boolean | | | task.editRules.startAtEditable | boolean | | | task.editRules.minSignupQuota | integer | | | participants | object[] | | | participants[].member | object | | | participants[].member.accountId | string | | | participants[].member.name | string | | | participants[].member.avatarUrl | string | 可能为 null | | participants[].member.departmentName | string | 可能为 null | | participants[].entry | object | 员工在某个任务上的参与记录 | | participants[].entry.id | string | | | participants[].entry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | participants[].entry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | participants[].entry.rewardAmount | number | 可能为 null | | participants[].entry.spentAmount | number | 可能为 null | | participants[].entry.updatedAt | string | | **响应示例** ```json { "task": { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [ { "key": "string", "type": "text", "label": "string", "required": true, "max": 0 } ], "pickupInfo": { "location": "string", "timeText": "string", "startAt": "string", "endAt": "string", "rules": "string" }, "status": "active", "scopeKind": "all", "scopeIds": [ "string" ], "signupQuota": 0, "budgetFrozen": 0, "stats": { "signedUp": 0, "joined": 0, "completed": 0, "redeemed": 0, "pendingReview": 0, "pendingWriteoff": 0 }, "version": 0, "editRules": { "locked": [ "string" ], "minQuota": 0, "pointsEditable": true, "startAtEditable": true, "minSignupQuota": 0 } }, "participants": [ { "member": { "accountId": "string", "name": "string", "avatarUrl": "string", "departmentName": "string" }, "entry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" } } ] } ``` **错误** - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 #### POST:提前结束 / 编辑任务 可选。`action: "end"` 提前结束,释放未用预算(待审核的份额先扣留),返回 `released`。 `action: "update"` 编辑:带上详情里的 `version` 作为 `expectedVersion`(乐观锁),只传要改的字段;结算方式、完成方式、审核方式、是否核销发布后不可改(见 `task.editRules.locked`)。奖励型改额度 / 名额 / 范围时按差额追加冻结或释放,返回 `budgetDelta`。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | taskId | string | 是 | | **请求体(application/json,发布与编辑任务的字段。消耗型恒为直接完成、自动审核;只有消耗型有核销与领取信息。)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 是 | 可选值:`end` / `update` | | expectedVersion | integer | 否 | update 时必传 | | title | string | 否 | 最长 30 | | description | string | 否 | 最长 500 | | coverUrl | string | 否 | 封面图 http(s) 地址,发布时必填;用「上传任务封面」拿到 | | category | string | 否 | 奖励型可选 training / learning / survey / activity / other;消耗型可选 festival / daily / activity / other。可选值:`training` / `learning` / `survey` / `activity` / `festival` / `daily` / `other` | | settleMode | string | 否 | reward 奖励额度(员工做任务赚)· consume 消耗额度(员工用额度兑换)。可选值:`reward` / `consume` | | points | integer | 否 | 每人奖励或消耗的额度(100 = 1 元)。≥ 1,≤ 10000000 | | quota | integer | 否 | 名额;不传 = 不限。≥ 1,≤ 100000。可能为 null | | scopeKind | string | 否 | 可选值:`all` / `departments` / `members`。默认 `"all"` | | scopeIds | string[] | 否 | 部门 id 或员工平台账号 id(scopeKind 非 all 时必填) | | startAt | string | 否 | 不传 = 立即开始 | | endAt | string | 否 | 截止时间,必填,须晚于开始时间与现在 | | needSignup | boolean | 否 | | | signupQuota | integer | 否 | ≥ 1。可能为 null | | completeMode | string | 否 | 仅奖励型:直接完成 / 提交结果。可选值:`direct` / `submit`。默认 `"direct"` | | reviewMode | string | 否 | 仅奖励型 + submit:缺省 manual 人工审核。可选值:`auto` / `manual` | | submitSchema | object[] | 否 | completeMode = submit 时必填。最多 10 项 | | submitSchema[].key | string | 是 | | | submitSchema[].type | string | 是 | 可选值:`text` / `image` / `file` / `link` | | submitSchema[].label | string | 是 | 最长 20 | | submitSchema[].required | boolean | 否 | | | submitSchema[].max | integer | 否 | text 字数 / link 长度 / image、file 个数(≤9)上限 | | needWriteoff | boolean | 否 | 仅消耗型:兑换后是否需要线下核销(发领取码) | | pickupInfo | object | 否 | 消耗型任务的领取信息 | | pickupInfo.location | string | 否 | | | pickupInfo.timeText | string | 否 | | | pickupInfo.startAt | string | 否 | | | pickupInfo.endAt | string | 否 | | | pickupInfo.rules | string | 否 | | **请求示例**(只含必填字段) ```json { "action": "end" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | task | object | 管理视角的任务 | | task.id | string | | | task.title | string | | | task.category | string | | | task.categoryLabel | string | | | task.description | string | | | task.coverUrl | string | 可能为 null | | task.settleMode | string | 可选值:`reward` / `consume` | | task.points | number | 每人奖励或消耗的额度(100 = 1 元) | | task.quota | integer | null = 不限。可能为 null | | task.remaining | integer | 可能为 null | | task.startAt | string | | | task.endAt | string | | | task.phase | string | 可选值:`not_started` / `ongoing` / `ended` | | task.needSignup | boolean | | | task.signupFull | boolean | | | task.completeMode | string | 可选值:`direct` / `submit` | | task.reviewMode | string | 可选值:`auto` / `manual` | | task.needWriteoff | boolean | | | task.scopeText | string | 如「全体员工」「财务部、仓储部」 | | task.submitSchema | object[] | | | task.submitSchema[].key | string | | | task.submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | task.submitSchema[].label | string | 最长 20 | | task.submitSchema[].required | boolean | | | task.submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | task.pickupInfo | object | 消耗型任务的领取信息 | | task.pickupInfo.location | string | | | task.pickupInfo.timeText | string | | | task.pickupInfo.startAt | string | | | task.pickupInfo.endAt | string | | | task.pickupInfo.rules | string | | | task.status | string | 可选值:`active` / `ended` / `cancelled` | | task.scopeKind | string | 可选值:`all` / `departments` / `members` | | task.scopeIds | string[] | | | task.signupQuota | integer | 可能为 null | | task.budgetFrozen | number | 已冻结的预算 | | task.stats | object | | | task.stats.signedUp | integer | | | task.stats.joined | integer | | | task.stats.completed | integer | | | task.stats.redeemed | integer | | | task.stats.pendingReview | integer | | | task.stats.pendingWriteoff | integer | | | task.version | integer | 编辑时作为 expectedVersion 带回 | | task.editRules | object | 前端据此置灰,服务端照样校验 | | task.editRules.locked | string[] | 当前不可改的字段名 | | task.editRules.minQuota | integer | | | task.editRules.pointsEditable | boolean | | | task.editRules.startAtEditable | boolean | | | task.editRules.minSignupQuota | integer | | | poolBalance | number | | | released | number | end:释放回额度池的额度 | | budgetDelta | number | update:追加(正)或释放(负)的额度 | **响应示例** ```json { "task": { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [ { "key": "string", "type": "text", "label": "string", "required": true, "max": 0 } ], "pickupInfo": { "location": "string", "timeText": "string", "startAt": "string", "endAt": "string", "rules": "string" }, "status": "active", "scopeKind": "all", "scopeIds": [ "string" ], "signupQuota": 0, "budgetFrozen": 0, "stats": { "signedUp": 0, "joined": 0, "completed": 0, "redeemed": 0, "pendingReview": 0, "pendingWriteoff": 0 }, "version": 0, "editRules": { "locked": [ "string" ], "minQuota": 0, "pointsEditable": true, "startAtEditable": true, "minSignupQuota": 0 } }, "poolBalance": 0, "released": 0, "budgetDelta": 0 } ``` **错误** - 400:`BAD_REQUEST` / `FIELD_LOCKED` / `QUOTA_TOO_SMALL` / `TASK_NOT_EDITABLE` / `POOL_INSUFFICIENT` - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 - 409:`VERSION_CONFLICT`:任务已被他人修改,刷新后重试 --- ### `POST /v1/enterprise/org/task-cover` — 管理员:上传任务封面(先换上传票据,再上传文件) 鉴权:用户态(可选接口);适用场景:员工福利购物 可选。两段式上传:先用本接口(签名 JSON)换一张 10 分钟有效、用一次即作废的票据,再把图片 POST multipart(字段名 `file`)或 PUT 裸 body 到返回的 `putPath`(凭票据鉴权,不需要签名),得到 `{ ok, url, key }`,把 `url` 填进任务的 `coverUrl`。只收 jpg / png / webp,按文件头识别。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | fileName | string | 否 | | | contentType | string | 否 | 例:`image/jpeg` | | size | integer | 否 | 字节数,超限直接拒 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | ticket | string | | | putPath | string | 上传地址(相对路径,拼在 API 域名后) | | maxBytes | integer | | | expiresInSec | integer | | **响应示例** ```json { "ok": true, "ticket": "string", "putPath": "string", "maxBytes": 0, "expiresInSec": 0 } ``` **错误** - 400:`TOO_LARGE` - 503:`STORAGE_UNAVAILABLE` --- ### `GET/POST /v1/enterprise/org/task-reviews` — 管理员:待审核的提交 / 批量通过或驳回(驳回须填原因) 鉴权:用户态(可选接口);适用场景:员工福利购物 #### GET:待审核的提交 可选。员工提交的结果,图片与文件带短时签名链接;`task.submitSchema` 用来把 payload 渲染成表单。rejected 只列每人最新一版。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | status | string | 否 | 可选值:`pending` / `rejected` / `all`。默认 `"pending"` | | taskId | string | 否 | | | cursor | string | 否 | 翻页游标:取上一页返回的 nextCursor,首页不传 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | counts | object | | | counts.all | integer | | | counts.pending | integer | | | counts.rejected | integer | | | items | object[] | | | items[].submission | object | | | items[].submission.id | string | | | items[].submission.version | integer | | | items[].submission.status | string | 可选值:`pending` / `approved` / `rejected` / `superseded` | | items[].submission.payload | object | text / link 为字符串;image / file 为 [{ key, url, name }],url 为短时签名链接 | | items[].submission.rejectReason | string | 可能为 null | | items[].submission.createdAt | string | | | items[].submission.reviewedAt | string | 可能为 null | | items[].member | object | | | items[].member.accountId | string | | | items[].member.name | string | | | items[].member.avatarUrl | string | 可能为 null | | items[].member.departmentName | string | 可能为 null | | items[].task | object | | | items[].task.id | string | | | items[].task.title | string | | | items[].task.category | string | | | items[].task.categoryLabel | string | | | items[].task.settleMode | string | | | items[].task.points | number | | | items[].task.submitSchema | object[] | | | items[].task.submitSchema[].key | string | | | items[].task.submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | items[].task.submitSchema[].label | string | 最长 20 | | items[].task.submitSchema[].required | boolean | | | items[].task.submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | nextCursor | string | 下一页游标;null = 没有下一页。可能为 null | **响应示例** ```json { "counts": { "all": 0, "pending": 0, "rejected": 0 }, "items": [ { "submission": { "id": "string", "version": 0, "status": "pending", "payload": null, "rejectReason": "string", "createdAt": "string", "reviewedAt": "string" }, "member": { "accountId": "string", "name": "string", "avatarUrl": "string", "departmentName": "string" }, "task": { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "settleMode": "string", "points": 0, "submitSchema": [] } } ], "nextCursor": "string" } ``` #### POST:审核通过 / 驳回 可选。批量审核,逐条各自处理:成功的 id 在 `ok` 数组里,失败的在 `failed`。通过即发放奖励;驳回必须填原因,员工可重新提交。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 是 | 可选值:`approve` / `reject` | | submissionIds | string[] | 是 | | | reason | string | 否 | reject 时必填 | **请求示例**(只含必填字段) ```json { "action": "approve", "submissionIds": [ "string" ] } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | string[] | 处理成功的 submissionId(注意此处 ok 是数组) | | failed | object[] | | | failed[].id | string | | | failed[].code | string | | | failed[].message | string | | **响应示例** ```json { "ok": [ "string" ], "failed": [ { "id": "string", "code": "string", "message": "string" } ] } ``` **错误** - 400:`BAD_REQUEST`:action 不对、没选提交或驳回没填原因 --- ### `GET/POST /v1/enterprise/org/task-redemptions` — 管理员:待核销兑换(可按码查)/ 核销或撤销(撤销退额度) 鉴权:用户态(可选接口);适用场景:员工福利购物 #### GET:兑换核销列表 / 按领取码查 可选。消耗型任务的兑换记录。缺省列待核销的;带 `code` 时按领取码查(查不到 items 为空)。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | status | string | 否 | entry 状态,如 pending_writeoff / completed / refunded / all;缺省 pending_writeoff(带 code 时缺省 all) | | code | string | 否 | 领取码 | | cursor | string | 否 | 翻页游标:取上一页返回的 nextCursor,首页不传 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].entry | object | 员工在某个任务上的参与记录 | | items[].entry.id | string | | | items[].entry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | items[].entry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | items[].entry.rewardAmount | number | 可能为 null | | items[].entry.spentAmount | number | 可能为 null | | items[].entry.updatedAt | string | | | items[].member | object | | | items[].member.accountId | string | | | items[].member.name | string | | | items[].member.avatarUrl | string | 可能为 null | | items[].member.departmentName | string | 可能为 null | | items[].task | object | | | items[].task.id | string | | | items[].task.title | string | | | items[].task.coverUrl | string | 可能为 null | | items[].task.points | number | | | items[].task.pickupInfo | object | 消耗型任务的领取信息 | | items[].task.pickupInfo.location | string | | | items[].task.pickupInfo.timeText | string | | | items[].task.pickupInfo.startAt | string | | | items[].task.pickupInfo.endAt | string | | | items[].task.pickupInfo.rules | string | | | items[].redeemedAt | string | | | nextCursor | string | 下一页游标;null = 没有下一页。可能为 null | **响应示例** ```json { "items": [ { "entry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" }, "member": { "accountId": "string", "name": "string", "avatarUrl": "string", "departmentName": "string" }, "task": { "id": "string", "title": "string", "coverUrl": "string", "points": 0, "pickupInfo": {} }, "redeemedAt": "string" } ], "nextCursor": "string" } ``` #### POST:核销 / 撤销兑换 可选。`writeoff` 核销(员工线下领取后);`revoke` 撤销兑换,额度退回员工、名额回补。用 `entryId` 或 `code` 指定。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 是 | 可选值:`writeoff` / `revoke` | | entryId | string | 否 | | | code | string | 否 | 领取码;与 entryId 二选一 | **请求示例**(只含必填字段) ```json { "action": "writeoff" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | entry | object | 员工在某个任务上的参与记录 | | entry.id | string | | | entry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | entry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | entry.rewardAmount | number | 可能为 null | | entry.spentAmount | number | 可能为 null | | entry.updatedAt | string | | **响应示例** ```json { "entry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" } } ``` **错误** - 400:`BAD_REQUEST` / `INVALID_CODE` / `INVALID_STATE` - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 --- ### `GET /v1/enterprise/tasks` — 员工:可参与的任务(?tab=earn|redeem) 鉴权:用户态(可选接口);适用场景:员工福利购物 可选。`tab=earn` 赚额度(奖励型)· `tab=redeem` 兑福利(消耗型)。只返回本人范围内、进行中的任务,带 `myEntry`。每页 20 条。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | tab | string | 否 | 可选值:`earn` / `redeem`。默认 `"earn"` | | cursor | string | 否 | 翻页游标:取上一页返回的 nextCursor,首页不传 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | | | items[].title | string | | | items[].category | string | | | items[].categoryLabel | string | | | items[].description | string | | | items[].coverUrl | string | 可能为 null | | items[].settleMode | string | 可选值:`reward` / `consume` | | items[].points | number | 每人奖励或消耗的额度(100 = 1 元) | | items[].quota | integer | null = 不限。可能为 null | | items[].remaining | integer | 可能为 null | | items[].startAt | string | | | items[].endAt | string | | | items[].phase | string | 可选值:`not_started` / `ongoing` / `ended` | | items[].needSignup | boolean | | | items[].signupFull | boolean | | | items[].completeMode | string | 可选值:`direct` / `submit` | | items[].reviewMode | string | 可选值:`auto` / `manual` | | items[].needWriteoff | boolean | | | items[].scopeText | string | 如「全体员工」「财务部、仓储部」 | | items[].submitSchema | object[] | | | items[].submitSchema[].key | string | | | items[].submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | items[].submitSchema[].label | string | 最长 20 | | items[].submitSchema[].required | boolean | | | items[].submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | items[].pickupInfo | object | 消耗型任务的领取信息 | | items[].pickupInfo.location | string | | | items[].pickupInfo.timeText | string | | | items[].pickupInfo.startAt | string | | | items[].pickupInfo.endAt | string | | | items[].pickupInfo.rules | string | | | items[].myEntry | object | 员工在某个任务上的参与记录 | | items[].myEntry.id | string | | | items[].myEntry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | items[].myEntry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | items[].myEntry.rewardAmount | number | 可能为 null | | items[].myEntry.spentAmount | number | 可能为 null | | items[].myEntry.updatedAt | string | | | items[].lastSubmission | object | 仅详情接口返回 | | items[].lastSubmission.id | string | | | items[].lastSubmission.version | integer | | | items[].lastSubmission.status | string | 可选值:`pending` / `approved` / `rejected` / `superseded` | | items[].lastSubmission.payload | object | text / link 为字符串;image / file 为 [{ key, url, name }],url 为短时签名链接 | | items[].lastSubmission.rejectReason | string | 可能为 null | | items[].lastSubmission.createdAt | string | | | items[].lastSubmission.reviewedAt | string | 可能为 null | | nextCursor | string | 下一页游标;null = 没有下一页。可能为 null | | balance | number | 员工当前额度余额 | **响应示例** ```json { "items": [ { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [ {} ], "pickupInfo": { "location": "string", "timeText": "string", "startAt": "string", "endAt": "string", "rules": "string" }, "myEntry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" }, "lastSubmission": { "id": "string", "version": 0, "status": "pending", "payload": null, "rejectReason": "string", "createdAt": "string", "reviewedAt": "string" } } ], "nextCursor": "string", "balance": 0 } ``` --- ### `GET /v1/enterprise/tasks/mine` — 员工:我参与的任务 / 我的兑换 鉴权:用户态(可选接口);适用场景:员工福利购物 可选。参与过的任务,按最近变动倒序,每页 20 条。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | kind | string | 否 | 可选值:`earn` / `redeem`。默认 `"earn"` | | cursor | string | 否 | 翻页游标:取上一页返回的 nextCursor,首页不传 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].task | object | 员工视角的任务 | | items[].task.id | string | | | items[].task.title | string | | | items[].task.category | string | | | items[].task.categoryLabel | string | | | items[].task.description | string | | | items[].task.coverUrl | string | 可能为 null | | items[].task.settleMode | string | 可选值:`reward` / `consume` | | items[].task.points | number | 每人奖励或消耗的额度(100 = 1 元) | | items[].task.quota | integer | null = 不限。可能为 null | | items[].task.remaining | integer | 可能为 null | | items[].task.startAt | string | | | items[].task.endAt | string | | | items[].task.phase | string | 可选值:`not_started` / `ongoing` / `ended` | | items[].task.needSignup | boolean | | | items[].task.signupFull | boolean | | | items[].task.completeMode | string | 可选值:`direct` / `submit` | | items[].task.reviewMode | string | 可选值:`auto` / `manual` | | items[].task.needWriteoff | boolean | | | items[].task.scopeText | string | 如「全体员工」「财务部、仓储部」 | | items[].task.submitSchema | object[] | | | items[].task.submitSchema[].key | string | | | items[].task.submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | items[].task.submitSchema[].label | string | 最长 20 | | items[].task.submitSchema[].required | boolean | | | items[].task.submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | items[].task.pickupInfo | object | 消耗型任务的领取信息 | | items[].task.pickupInfo.location | string | | | items[].task.pickupInfo.timeText | string | | | items[].task.pickupInfo.startAt | string | | | items[].task.pickupInfo.endAt | string | | | items[].task.pickupInfo.rules | string | | | items[].task.myEntry | object | 员工在某个任务上的参与记录 | | items[].task.myEntry.id | string | | | items[].task.myEntry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | items[].task.myEntry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | items[].task.myEntry.rewardAmount | number | 可能为 null | | items[].task.myEntry.spentAmount | number | 可能为 null | | items[].task.myEntry.updatedAt | string | | | items[].task.lastSubmission | object | 仅详情接口返回 | | items[].task.lastSubmission.id | string | | | items[].task.lastSubmission.version | integer | | | items[].task.lastSubmission.status | string | 可选值:`pending` / `approved` / `rejected` / `superseded` | | items[].task.lastSubmission.payload | object | text / link 为字符串;image / file 为 [{ key, url, name }],url 为短时签名链接 | | items[].task.lastSubmission.rejectReason | string | 可能为 null | | items[].task.lastSubmission.createdAt | string | | | items[].task.lastSubmission.reviewedAt | string | 可能为 null | | items[].entry | object | 员工在某个任务上的参与记录 | | items[].entry.id | string | | | items[].entry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | items[].entry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | items[].entry.rewardAmount | number | 可能为 null | | items[].entry.spentAmount | number | 可能为 null | | items[].entry.updatedAt | string | | | nextCursor | string | 下一页游标;null = 没有下一页。可能为 null | **响应示例** ```json { "items": [ { "task": { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [], "pickupInfo": {}, "myEntry": {}, "lastSubmission": {} }, "entry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" } } ], "nextCursor": "string" } ``` --- ### `GET/POST /v1/enterprise/tasks/{taskId}` — 员工:任务详情 / 报名、完成、提交、兑换(带 idempotencyKey) 鉴权:用户态(可选接口);适用场景:员工福利购物 #### GET:任务详情 可选。含我的参与记录与最近一次提交(含驳回原因)。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | taskId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | task | object | 员工视角的任务 | | task.id | string | | | task.title | string | | | task.category | string | | | task.categoryLabel | string | | | task.description | string | | | task.coverUrl | string | 可能为 null | | task.settleMode | string | 可选值:`reward` / `consume` | | task.points | number | 每人奖励或消耗的额度(100 = 1 元) | | task.quota | integer | null = 不限。可能为 null | | task.remaining | integer | 可能为 null | | task.startAt | string | | | task.endAt | string | | | task.phase | string | 可选值:`not_started` / `ongoing` / `ended` | | task.needSignup | boolean | | | task.signupFull | boolean | | | task.completeMode | string | 可选值:`direct` / `submit` | | task.reviewMode | string | 可选值:`auto` / `manual` | | task.needWriteoff | boolean | | | task.scopeText | string | 如「全体员工」「财务部、仓储部」 | | task.submitSchema | object[] | | | task.submitSchema[].key | string | | | task.submitSchema[].type | string | 可选值:`text` / `image` / `file` / `link` | | task.submitSchema[].label | string | 最长 20 | | task.submitSchema[].required | boolean | | | task.submitSchema[].max | integer | text 字数 / link 长度 / image、file 个数(≤9)上限 | | task.pickupInfo | object | 消耗型任务的领取信息 | | task.pickupInfo.location | string | | | task.pickupInfo.timeText | string | | | task.pickupInfo.startAt | string | | | task.pickupInfo.endAt | string | | | task.pickupInfo.rules | string | | | task.myEntry | object | 员工在某个任务上的参与记录 | | task.myEntry.id | string | | | task.myEntry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | task.myEntry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | task.myEntry.rewardAmount | number | 可能为 null | | task.myEntry.spentAmount | number | 可能为 null | | task.myEntry.updatedAt | string | | | task.lastSubmission | object | 仅详情接口返回 | | task.lastSubmission.id | string | | | task.lastSubmission.version | integer | | | task.lastSubmission.status | string | 可选值:`pending` / `approved` / `rejected` / `superseded` | | task.lastSubmission.payload | object | text / link 为字符串;image / file 为 [{ key, url, name }],url 为短时签名链接 | | task.lastSubmission.rejectReason | string | 可能为 null | | task.lastSubmission.createdAt | string | | | task.lastSubmission.reviewedAt | string | 可能为 null | | balance | number | | **响应示例** ```json { "task": { "id": "string", "title": "string", "category": "string", "categoryLabel": "string", "description": "string", "coverUrl": "string", "settleMode": "reward", "points": 0, "quota": 0, "remaining": 0, "startAt": "string", "endAt": "string", "phase": "not_started", "needSignup": true, "signupFull": true, "completeMode": "direct", "reviewMode": "auto", "needWriteoff": true, "scopeText": "string", "submitSchema": [ { "key": "string", "type": "text", "label": "string", "required": true, "max": 0 } ], "pickupInfo": { "location": "string", "timeText": "string", "startAt": "string", "endAt": "string", "rules": "string" }, "myEntry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" }, "lastSubmission": { "id": "string", "version": 0, "status": "pending", "payload": null, "rejectReason": "string", "createdAt": "string", "reviewedAt": "string" } }, "balance": 0 } ``` **错误** - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 #### POST:报名 / 完成 / 提交 / 兑换 可选。`signup` 报名 · `complete` 直接完成(发奖励)· `submit` 提交结果(`payload` 按任务 `submitSchema` 组织:text / link 填字符串,image / file 填 `[{ key, name }]`,key 来自「上传任务凭证」)· `redeem` 用额度兑换(消耗型)。重复操作返回第一次的结果。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | taskId | string | 是 | | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 是 | 可选值:`signup` / `complete` / `submit` / `redeem` | | payload | object | 否 | 仅 submit:键为 submitSchema[].key | | idempotencyKey | string | 否 | | **请求示例**(只含必填字段) ```json { "action": "signup" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | entry | object | 员工在某个任务上的参与记录 | | entry.id | string | | | entry.status | string | 可选值:`signed_up` / `in_progress` / `submitted` / `rejected` / `completed` / `pending_writeoff` / `refunded` / `expired` | | entry.redeemCode | string | 需核销的兑换才有领取码。可能为 null | | entry.rewardAmount | number | 可能为 null | | entry.spentAmount | number | 可能为 null | | entry.updatedAt | string | | | balance | number | 操作后余额 | | rewarded | number | 本次获得的额度 | | spent | number | 本次消耗的额度 | **响应示例** ```json { "entry": { "id": "string", "status": "signed_up", "redeemCode": "string", "rewardAmount": 0, "spentAmount": 0, "updatedAt": "string" }, "balance": 0, "rewarded": 0, "spent": 0 } ``` **错误** - 400:`TASK_NOT_STARTED` / `TASK_ENDED` / `SIGNUP_REQUIRED` / `SIGNUP_FULL` / `QUOTA_FULL` / `INSUFFICIENT_POINTS` / `ALREADY_DONE` / `INVALID_STATE` / `BAD_REQUEST` - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 --- ### `POST /v1/enterprise/task-proof` — 员工:上传任务凭证(先换上传票据,再上传文件) 鉴权:用户态(可选接口);适用场景:员工福利购物 可选。两段式上传:先用本接口(签名 JSON)换一张 10 分钟有效的票据,再把文件 POST multipart(字段名 `file`)或 PUT 裸 body 到返回的 `putPath`(凭票据鉴权,不需要签名),得到 `{ ok, key, url, name }`。提交任务时 payload 里传 `{ key, name }`;`url` 是短时签名链接,只用于立即预览。支持 jpg / png / webp 图片(≤10MB)与 pdf / doc(x) / xls(x) 文件(≤20MB),按文件头识别。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | taskId | string | 是 | | | fileName | string | 否 | Office 文件靠后缀区分格式,建议带上 | | contentType | string | 否 | image/* 按图片限额,其余按文件限额 | | size | integer | 否 | 字节数,超限直接拒 | **请求示例**(只含必填字段) ```json { "taskId": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | ticket | string | | | putPath | string | 上传地址(相对路径,拼在 API 域名后) | | maxBytes | integer | | | expiresInSec | integer | | **响应示例** ```json { "ok": true, "ticket": "string", "putPath": "string", "maxBytes": 0, "expiresInSec": 0 } ``` **错误** - 400:`BAD_REQUEST` 缺 taskId / `TOO_LARGE` / `INVALID_STATE` 该任务无需提交凭证 / `TASK_ENDED` - 404:`TASK_NOT_FOUND`:任务不存在、已下架或不属于本企业 - 503:`STORAGE_UNAVAILABLE` ## 商品 商品接口正在重构为统一商品层,届时所有场景用同一套接口、同一种商品 ID。在那之前员工福利与企业采购用 /v1/enterprise/*,消费者购物用 /v1/lm/*,每条接口标了适用场景。按关键词或类目找商品都用搜索,不提供翻完整个货盘的列表接口。 ### `GET /v1/enterprise/products/{id}` — 商品详情 鉴权:appKey;适用场景:员工福利购物 / 企业采购 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | id | string | 商品 ID,下单时原样放进 items[].productId | | externalItemId | string | | | title | string | | | subtitle | string | | | imageUrl | string | | | imageUrls | string[] | | | category | string | | | brand | string | | | price | number | 售价(元);多规格商品为最低规格价 | | marketPrice | number | | | shopName | string | | | sales30d | number | | | availability | string | 可选值:`in_stock` / `out_of_stock` | | featured | boolean | 是否运营精选 | | matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | matchedSku.skuId | string | | | matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | description | string | | | detailImages | string[] | | | specs | object | | | skus | object[] | 只有一个规格且无 skuId 时不返回 | | skus[].skuId | string | null = 下单时不传 skuId;"0" 是真实 id,要原样传。可能为 null | | skus[].specs | object | | | skus[].price | number | | | skus[].stock | number | | | skus[].image | string | | **响应示例** ```json { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [ "string" ], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": { "skuId": "string", "specText": "string", "price": 0, "imageUrl": "string" }, "description": "string", "detailImages": [ "string" ], "specs": null, "skus": [ { "skuId": "string", "specs": null, "price": 0, "stock": 0, "image": "string" } ] } ``` **错误** - 404:`NOT_FOUND`:商品不存在或已下架 --- ### `GET /v1/enterprise/products/batch` — 商品批量详情(ids 逗号分隔,最多 20 件) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 一次查多件商品的详情(购物车 / 收藏 / 订单回显用),每件与「商品详情」同一结构、同一可见范围。按请求顺序返回 `items`;查不到或已下架的放进 `notFound`,不报错。一次最多 20 件,超过回 `TOO_MANY_IDS`。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | ids | string | 是 | 商品 id,英文逗号分隔,最多 20 个,如 `ep_self_1,ep_self_2` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | 商品 ID,下单时原样放进 items[].productId | | items[].externalItemId | string | | | items[].title | string | | | items[].subtitle | string | | | items[].imageUrl | string | | | items[].imageUrls | string[] | | | items[].category | string | | | items[].brand | string | | | items[].price | number | 售价(元);多规格商品为最低规格价 | | items[].marketPrice | number | | | items[].shopName | string | | | items[].sales30d | number | | | items[].availability | string | 可选值:`in_stock` / `out_of_stock` | | items[].featured | boolean | 是否运营精选 | | items[].matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | items[].matchedSku.skuId | string | | | items[].matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | items[].matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | items[].matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | items[].description | string | | | items[].detailImages | string[] | | | items[].specs | object | | | items[].skus | object[] | 只有一个规格且无 skuId 时不返回 | | items[].skus[].skuId | string | null = 下单时不传 skuId;"0" 是真实 id,要原样传。可能为 null | | items[].skus[].specs | object | | | items[].skus[].price | number | | | items[].skus[].stock | number | | | items[].skus[].image | string | | | notFound | string[] | 查不到或当前不可见的商品 id | **响应示例** ```json { "items": [ { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [ "string" ], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": { "skuId": "string", "specText": "string", "price": 0, "imageUrl": "string" }, "description": "string", "detailImages": [ "string" ], "specs": null, "skus": [ {} ] } ], "notFound": [ "string" ] } ``` **错误** - 400:`BAD_REQUEST`:ids 为空;`TOO_MANY_IDS`:超过 20 件 --- ### `GET /v1/enterprise/products/by-tag` — 按标签取商品(tags 逗号分隔,match=any/all,支持按销量 / 价格 / 上架 / 打标时间排序或随机打散) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 取运营打了指定标签的商品,标签 key 向平台运营索取。商品结构与商品列表一致,可见范围为已上架 + 本渠道可见 + 有货。实际生效的标签回在 `tags`(已剔除停用 / 不存在的):`match=any` 时忽略无效标签、全部无效返回空列表;`match=all` 时有一个无效即返回空列表。未带 x-open-user 时只能取第一页(翻页返回 401 NEED_LOGIN),排序不受限。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | tags | string | 是 | 标签 key,英文逗号分隔(也可重复传 tags=a&tags=b),最多 20 个,超出的忽略 | | match | string | 否 | any:带任一标签即可;all:须同时带齐所有标签。可选值:`any` / `all`。默认 `"any"` | | sortBy | string | 否 | sales_desc 销量从高到低(销量为分档值,同档按更新时间);price_asc / price_desc 按售价;newest 按上架时间,新品在前;tagged 按打标时间,运营最近打上该标签的在前;random 随机打散,同一用户一小时内顺序固定、翻页不重不漏,每小时换一次(未带 x-open-user 时同一 appKey 下所有访客同一顺序;命中超过 2000 件时按 sales_desc 返回)。可选值:`sales_desc` / `price_asc` / `price_desc` / `newest` / `tagged` / `random`。默认 `"sales_desc"` | | page | integer | 否 | 默认 `1`。≥ 1 | | pageSize | integer | 否 | 默认 `20`。≥ 1,≤ 100 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | 商品 ID,下单时原样放进 items[].productId | | items[].externalItemId | string | | | items[].title | string | | | items[].subtitle | string | | | items[].imageUrl | string | | | items[].imageUrls | string[] | | | items[].category | string | | | items[].brand | string | | | items[].price | number | 售价(元);多规格商品为最低规格价 | | items[].marketPrice | number | | | items[].shopName | string | | | items[].sales30d | number | | | items[].availability | string | 可选值:`in_stock` / `out_of_stock` | | items[].featured | boolean | 是否运营精选 | | items[].matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | items[].matchedSku.skuId | string | | | items[].matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | items[].matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | items[].matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | page | integer | | | pageSize | integer | | | total | integer | 命中总数(精确值) | | hasMore | boolean | | | tags | string[] | 实际生效的标签 key(已剔除停用 / 不存在的) | **响应示例** ```json { "items": [ { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [ "string" ], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": { "skuId": "string", "specText": "string", "price": 0, "imageUrl": "string" } } ], "page": 0, "pageSize": 0, "total": 0, "hasMore": true, "tags": [ "string" ] } ``` **错误** - 400:`BAD_REQUEST`:tags 为空,或 sortBy 不在可选值内 --- ### `GET /v1/enterprise/products/{id}/desc` — 图文详情(长图文,单独缓存) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 已消毒的 HTML 片段,可直接渲染。拿不到时返回空串(仍为 200)。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | html | string | | | imageCount | integer | | **响应示例** ```json { "html": "string", "imageCount": 0 } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `POST /v1/enterprise/products/search` — 搜索 / 按条件浏览:商品 + 推荐规格,可附符合程度(mode=strict 只要完全符合的) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 请求体带 version: 2(响应同样带 version: 2);不带 version 为旧版接口,返回格式不同,保留一个版本周期。按关键词 / 编码找商品,或按条件浏览。每条结果是「商品 + 推荐规格」,可附上符合程度与每个条件的判定(include: ["match"])。mode 控制多严:缺省 balanced(完全符合的在前、一件都没有才放宽);AI 助手推荐、清单解析建议 strict(只要完全符合的)。翻页用 nextCursor。匹配与排序规则、各商品池可用的筛选字段见开发者文档 §11。未带 x-open-user 时带 query、筛选或排序都返回 401 NEED_LOGIN,纯浏览只给第一页。 **请求体(application/json,必须带 version: 2,其余全部可选;不传 query = 按条件浏览。不认识的参数一律 400 并在 field 里指明(带了旧参数会提示新写法)。不带 version 的请求按旧版接口处理(keyword / category / brand / priceMin / priceMax / inStockOnly / sortBy / page / pageSize,返回旧的 { items, page, pageSize, total }),保留一个版本周期)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | version | integer | 是 | 接口版本,固定传 2。不传 = 旧版接口(返回格式不同)。可选值:`2` | | query | object | 否 | 找什么:text 与 code 二选一 | | query.text | string | 否 | 关键词。多个条件用空格分开,必须条件全部满足才算完全符合。最长 100 | | query.optional | string[] | 否 | text 里「有更好、没有也行」的词(如用户说颜色无所谓):只参与排序,不作为必须条件。必须是 text 里出现过的词,否则 400。最多 10 项 | | query.code | string | 否 | 按 SKU 编码 / 型号 / 条码 / 上游商品 ID 精确查,不容错、不改写。最长 64 | | filter | object | 否 | 硬条件:不满足就不返回 | | filter.category | string \| string[] | 否 | 叶子类目名,精确匹配;数组 = 任一 | | filter.categoryId | string \| string[] | 否 | 类目 id(一级 / 二级 / 叶子),含子类目;数组 = 任一。类目导航接口给的就是它 | | filter.brand | string \| string[] | 否 | 品牌名,精确匹配;数组 = 任一 | | filter.price | object | 否 | 价格区间(元,含边界),按规格价:任一可售规格落在区间内即命中,此时推荐的就是区间内的规格。传反了自动对调 | | filter.price.gte | number | 否 | ≥ 0 | | filter.price.lte | number | 否 | ≥ 0 | | filter.inStock | boolean | 否 | 只要有货的 | | unknown | string | 否 | 筛选字段没有值的商品怎么处理(当前可用字段都有值,预留)。可选值:`include` / `exclude`。默认 `"include"` | | mode | string | 否 | 多严。balanced:完全符合的在前、部分符合的随后,一件都没有时才放宽(返回 relaxation);strict:只要完全符合的,宁缺毋滥(AI 助手推荐、清单解析用);broad:全部给,含放宽得到的。可选值:`balanced` / `strict` / `broad`。默认 `"balanced"` | | sort | string | 否 | 顺序。价格按推荐规格的价格;任何排序下不符合的(related)都排在最后。可选值:`relevance` / `price_asc` / `price_desc` / `sales_desc`。默认 `"relevance"` | | profile | string | 否 | 排序预设:agent 推荐给人看的少量结果(符合程度优先,其次有货);mall 搜索结果页。可选值:`agent` / `mall`。默认 `"agent"` | | prefer | object[] | 否 | 软偏好:只影响同一符合程度内的先后,不影响返回哪些;多条按先后递减。sort 不是 relevance 时忽略。每条是以下三种写法之一:`{ "field": "price", "direction": "low" \| "high" }` 便宜 / 贵的优先;`{ "field": "brand", "value": "膳魔师" }` 这个品牌优先;`{ "text": "大容量" }` 这个词命中的优先。最多 5 项 | | excludeFields | string[] | 否 | 这次查询不用这些字段(只对 query.text 起作用):既不在里面找商品,也不拿它判断符合与否。用来对比某个字段的作用,如去掉卖点 sellingPoints。不能全部去掉。可选字段:title(标题)、titleGrams(标题按每两个字切开(中文分词切错时的兜底))、aliases(买家叫法(别名))、subtitle(副标题)、brand(品牌)、category(叶子类目名)、categoryPath(类目整条路径)、tags(平台类目路径)、skuSpecValues(各规格的规格值(颜色、尺码、容量、型号…)与材质)、skuTitles(各规格的规格名)、specsText(商品参数(前 600 字))、qualityPerformance(品质性能(前 300 字))、useCases(适用场景)、descriptionSellingPoints(商品描述与卖点(前 300 字))、audience(适用人群)、exactCodes(编码:上游商品 ID、SKU 编码、型号、条码)、supplierName(供应商名)。可选值:`title` / `titleGrams` / `aliases` / `subtitle` / `brand` / `category` / `categoryPath` / `tags` / `skuSpecValues` / `skuTitles` / `specsText` / `qualityPerformance` / `useCases` / `descriptionSellingPoints` / `audience` / `exactCodes` / `supplierName` | | limit | integer | 否 | 默认 `20`。≥ 1,≤ 50 | | cursor | string | 否 | 翻页:上次返回的 nextCursor。与本次请求的条件绑定(换了条件 400),1 小时有效 | | include | string[] | 否 | match:每条结果附上条件判定(符合程度、每个条件满足与否及凭据)。可选值:`match` | **请求示例**(只含必填字段) ```json { "version": 2 } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | version | integer | 响应版本,固定 2。解析前可以校验它,防止拿旧格式硬解析。可选值:`2` | | searchId | string | 带 query 时返回;上报点击 / 加购 / 下单时带回 | | interpretation | object | 带 query.text 时返回:我们怎么理解这次查询(供参考,不是约定) | | interpretation.searched | string | 纠错 / 改写后实际搜的词;与输入不同时可提示「已为您搜索 xx」 | | interpretation.requirements | object[] | | | interpretation.requirements[].text | string | | | interpretation.requirements[].role | string | product 品类 / attribute 属性 / brand 品牌 / other 其他(编码)。可选值:`product` / `attribute` / `brand` / `other` | | interpretation.requirements[].enforced | boolean | 是否作为必须条件(决定完全符合与否)。只有有把握的条件才是 true | | interpretation.requirements[].why | string | 不作为必须条件的原因:调用方标了可选 / 模糊词(大容量、好用)/ 认不出。可选值:`optional` / `vague` / `unrecognized` | | hits | object[] | | | hits[].product | object | | | hits[].product.id | string | 商品 ID,下单时原样放进 items[].productId | | hits[].product.externalItemId | string | | | hits[].product.title | string | | | hits[].product.subtitle | string | | | hits[].product.imageUrl | string | | | hits[].product.imageUrls | string[] | | | hits[].product.category | string | | | hits[].product.brand | string | | | hits[].product.price | number | 售价(元);多规格商品为最低规格价 | | hits[].product.marketPrice | number | | | hits[].product.shopName | string | | | hits[].product.sales30d | number | | | hits[].product.availability | string | 可选值:`in_stock` / `out_of_stock` | | hits[].product.featured | boolean | 是否运营精选 | | hits[].product.matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | hits[].product.matchedSku.skuId | string | | | hits[].product.matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | hits[].product.matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | hits[].product.matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | hits[].product.categoryId | string | 叶子类目 id(仅企业购) | | hits[].sku | object | 推荐的规格;商品没有可售规格时为 null | | hits[].sku.id | string | 规格 ID,即详情接口的 skus[].skuId;单规格商品(详情里没有规格选择)不给 | | hits[].sku.specText | string | 规格值,如「曜石黑 / 1000ml」 | | hits[].sku.specs | object | 规格名 → 规格值 | | hits[].sku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径 | | hits[].sku.marketPrice | number | | | hits[].sku.imageUrl | string | 规格图;没有时用商品主图 | | hits[].sku.stock | integer | | | hits[].sku.available | boolean | | | hits[].sku.chosenBy | string | match 按搜索条件选出 / cheapest 条件在规格间没有区分,给价格区间内最便宜的 / only 只有一个规格。可选值:`match` / `cheapest` / `only` | | hits[].skuCount | integer | 可售规格数 | | hits[].match | object | include 含 match 时返回 | | hits[].match.level | string | exact 推荐的这个规格满足全部必须条件 / partial 没有不满足的,但有判断不了或分散在不同规格上的 / related 有不满足的,或是放宽得到的。可选值:`exact` / `partial` / `related` | | hits[].match.requirements | object[] | 每个条件在推荐规格上的判定,顺序同 interpretation.requirements | | hits[].match.requirements[].text | string | | | hits[].match.requirements[].state | string | met 满足 / unmet 不满足(如类目明确是别的品类)/ unknown 判断不了(字面上没找到不算不满足)。可选值:`met` / `unmet` / `unknown` | | hits[].match.requirements[].by | string | 满足的凭据:命中的规格值原文,如「曜石黑」 | | relaxation | object | 返回了不符合(related)的结果时才有:哪些必须条件没有满足。可提示「没有找到同时满足…的商品,以下是相关商品」 | | relaxation.dropped | string[] | | | relaxHints | object[] | 完全符合的不足 limit 时:去掉某个必须条件能有几件完全符合的。AI 助手可据此问用户要不要放宽,再把那个词放进 query.optional 重搜 | | relaxHints[].drop | string | | | relaxHints[].exact | integer | | | total | object | | | total.value | integer | | | total.exact | boolean | false = 估算值 | | nextCursor | string | 下一页的游标;没有 = 没有下一页。未登录访客不返回 | | degraded | boolean | 搜索服务暂时不可用、退回查库:只按标题拆词匹配,没有 match 与推荐规格的条件判定 | **响应示例** ```json { "version": 2, "searchId": "string", "interpretation": { "searched": "string", "requirements": [ { "text": "string", "role": "product", "enforced": true, "why": "optional" } ] }, "hits": [ { "product": { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": {}, "categoryId": "string" }, "sku": { "id": "string", "specText": "string", "specs": null, "price": 0, "marketPrice": 0, "imageUrl": "string", "stock": 0, "available": true, "chosenBy": "match" }, "skuCount": 0, "match": { "level": "exact", "requirements": [] } } ], "relaxation": { "dropped": [ "string" ] }, "relaxHints": [ { "drop": "string", "exact": 0 } ], "total": { "value": 0, "exact": true }, "nextCursor": "string", "degraded": true } ``` **错误** - 400:`BAD_REQUEST`:参数不合法(field 指明哪个参数;带了旧参数会提示新写法),version 不是 2,或 cursor 无效 / 过期 / 与本次条件不符 --- ### `GET /v1/enterprise/nav` — 类目导航 · 一级 鉴权:appKey;适用场景:员工福利购物 / 企业采购 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].groupId | string | | | items[].title | string | | | items[].icon | string | 可能为 null | | items[].entries | object[] | | | items[].entries[].label | string | | | items[].entries[].categoryId | string | | | items[].entries[].categoryName | string | | | items[].entries[].count | integer | | **响应示例** ```json { "items": [ { "groupId": "string", "title": "string", "icon": "string", "entries": [ {} ] } ] } ``` --- ### `GET /v1/enterprise/nav/branch` — 类目导航 · 二级(带图) 鉴权:appKey;适用场景:员工福利购物 / 企业采购 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | ids | string | 是 | 一级类目 id,逗号分隔,最多 20 个 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].categoryId | string | | | items[].name | string | | | items[].children | object[] | 每个一级最多 12 个 | | items[].children[].categoryId | string | | | items[].children[].name | string | | | items[].children[].count | integer | | | items[].children[].imageUrl | string | 可能为 null | | items[].children[].imageKind | string | 可选值:`url` / `svg`。可能为 null | | items[].children[].monogram | object | 无图时的文字占位 | | items[].children[].monogram.text | string | | | items[].children[].monogram.hue | number | | **响应示例** ```json { "items": [ { "categoryId": "string", "name": "string", "children": [ {} ] } ] } ``` **错误** - 400:参数不合法 --- ### `GET /v1/enterprise/zones` — 首页专区(运营位 banner),点开用下一条取商品 鉴权:appKey(可选接口);适用场景:员工福利购物 / 企业采购 可选。运营配置的专区(一张 banner + 一组商品),按 `sort` 顺序渲染 banner,点击后用 `id` 调专区商品接口。停用的专区不出现。未登录访客浏览(平台为该应用配了访客货盘时)返回空列表。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | | | items[].name | string | | | items[].bannerUrl | string | | | items[].sort | number | | **响应示例** ```json { "items": [ { "id": "string", "name": "string", "bannerUrl": "string", "sort": 0 } ] } ``` --- ### `GET /v1/enterprise/zones/{id}/products` — 专区商品 鉴权:appKey(可选接口);适用场景:员工福利购物 / 企业采购 可选。商品结构与商品列表一致,按销量倒序。专区不存在、已停用或访客浏览时返回空列表(`zone` 为 null 或 items 为空),不返回 404。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | 专区 id | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | page | integer | 否 | 默认 `1`。≥ 1 | | pageSize | integer | 否 | 默认 `20`。≥ 1,≤ 100 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | 商品 ID,下单时原样放进 items[].productId | | items[].externalItemId | string | | | items[].title | string | | | items[].subtitle | string | | | items[].imageUrl | string | | | items[].imageUrls | string[] | | | items[].category | string | | | items[].brand | string | | | items[].price | number | 售价(元);多规格商品为最低规格价 | | items[].marketPrice | number | | | items[].shopName | string | | | items[].sales30d | number | | | items[].availability | string | 可选值:`in_stock` / `out_of_stock` | | items[].featured | boolean | 是否运营精选 | | items[].matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | items[].matchedSku.skuId | string | | | items[].matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | items[].matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | items[].matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | page | integer | | | pageSize | integer | | | total | integer | 命中总数(带关键词时为估算值)。结果按渠道可见范围再过滤,一页可能少于 pageSize;翻页以返回为空或 page × pageSize ≥ total 判断结束 | | searchId | string | 带关键词搜索时返回;上报点击 / 加购 / 下单时带回 | | correctedQuery | string | 做了错别字纠正时实际搜的词,可提示「已为您搜索 xx」 | | relaxed | boolean | true = 没有同时满足全部关键词的商品,返回的是放宽后的相关商品;可提示「没有找到同时满足『…』的商品,以下是相关商品」 | | zone | object | 可能为 null | | zone.id | string | | | zone.name | string | | | zone.bannerUrl | string | | | hasMore | boolean | | **响应示例** ```json { "items": [ { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [ "string" ], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": { "skuId": "string", "specText": "string", "price": 0, "imageUrl": "string" } } ], "page": 0, "pageSize": 0, "total": 0, "searchId": "string", "correctedQuery": "string", "relaxed": true, "zone": { "id": "string", "name": "string", "bannerUrl": "string" }, "hasMore": true } ``` --- ### `GET /v1/enterprise/bundles` — 组货方案列表(按调用方所属产品,按场景分组,如「新企开办 → 1人团队」) 鉴权:appKey(可选接口);适用场景:员工福利购物 / 企业采购 可选。平台运营配置的组货方案(如「新企开办 → 1人团队 / 5人团队」:一组规格 + 建议数量),按场景分组;场景、方案各自按运营设的顺序。只返回调用方所属产品(appKey 的产品归属)里已上线的方案。appKey 未配置所属产品时须传 `realm`;配置了的传别的产品返回 403。列表不含明细,选中方案后用 `code` 调组货方案详情。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | scene | string | 否 | 只看某个场景(场景编码,如 business_startup) | | realm | string | 否 | 所属产品。仅 appKey 未配置所属产品时需要。可选值:`welfare` / `procurement` / `consumer` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | realm | string | 实际生效的产品 | | scenes | object[] | | | scenes[].code | string | 场景编码 | | scenes[].name | string | 场景名,如「新企开办」 | | scenes[].bundles | object[] | | | scenes[].bundles[].code | string | 方案编码,稳定不变,用于取详情 | | scenes[].bundles[].name | string | 方案名称 | | scenes[].bundles[].label | string | 前端选项标签,如「1人团队」 | | scenes[].bundles[].description | string | 可能为 null | | scenes[].bundles[].sortOrder | integer | | | scenes[].bundles[].version | integer | 当前发布的版本号,运营每次发布 +1 | | scenes[].bundles[].itemCount | integer | 规格数 | | scenes[].bundles[].publishedAt | string | 可能为 null | **响应示例** ```json { "realm": "string", "scenes": [ { "code": "string", "name": "string", "bundles": [ {} ] } ] } ``` **错误** - 400:`BAD_REQUEST`:appKey 未配置所属产品且没传 realm,或 realm 不认识 --- ### `GET /v1/enterprise/bundles/{code}` — 组货方案详情:规格 + 建议数量,价格库存实时,买不到的带原因 鉴权:appKey(可选接口);适用场景:员工福利购物 / 企业采购 可选。方案当前发布版本的规格与建议数量,价格、库存实时读取,并按调用方渠道判断能否购买。买不到的规格也会返回(`available=false` 并带 `unavailableReason`),由端上决定置灰还是提示换货;`totalPrice` 只合计能买的规格。加购 / 下单沿用 `{ productId, skuId?, qty }`:`qty` 取 `quantity`,单规格商品 `skuId` 为 null,不传。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | code | string | 是 | 方案编码(来自组货方案列表) | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | realm | string | 否 | 所属产品。仅 appKey 未配置所属产品时需要。可选值:`welfare` / `procurement` / `consumer` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | code | string | | | name | string | | | label | string | | | description | string | 可能为 null | | sortOrder | integer | | | version | integer | | | itemCount | integer | | | publishedAt | string | 可能为 null | | scene | object | | | scene.code | string | | | scene.name | string | | | totalPrice | number | 能买的规格按建议数量的合计(元),参考价,以结算为准 | | unavailableCount | integer | 当前买不到的规格数 | | items | object[] | | | items[].skuRef | string | 规格的稳定标识 | | items[].productId | string | 加购 / 下单用的商品 ID | | items[].skuId | string | 加购 / 下单用的规格 ID;单规格商品为 null。可能为 null | | items[].quantity | integer | 建议数量 | | items[].title | string | | | items[].specs | object | 规格属性,如 { 颜色: 黑色 } | | items[].skuTitle | string | 可能为 null | | items[].imageUrl | string | | | items[].brand | string | 可能为 null | | items[].price | number | 单价(元),实时 | | items[].marketPrice | number | 可能为 null | | items[].stock | integer | 精确库存;上游只给模糊库存时为 null,看 fuzzyStock。可能为 null | | items[].fuzzyStock | string | 可能为 null | | items[].available | boolean | | | items[].unavailableReason | string | available=false 时才有。可选值:`商品未上架` / `上游已下架` / `规格已删除` / `无货` / `规格不存在` / `渠道不可售` | **响应示例** ```json { "code": "string", "name": "string", "label": "string", "description": "string", "sortOrder": 0, "version": 0, "itemCount": 0, "publishedAt": "string", "scene": { "code": "string", "name": "string" }, "totalPrice": 0, "unavailableCount": 0, "items": [ { "skuRef": "string", "productId": "string", "skuId": "string", "quantity": 0, "title": "string", "specs": null, "skuTitle": "string", "imageUrl": "string", "brand": "string", "price": 0, "marketPrice": 0, "stock": 0, "fuzzyStock": "string", "available": true, "unavailableReason": "商品未上架" } ] } ``` **错误** - 400:`BAD_REQUEST`:appKey 未配置所属产品且没传 realm,或 realm 不认识 - 404:`NOT_FOUND`:方案不存在、未上线或不在该产品里 --- ### `GET /v1/enterprise/products/suggest` — 搜索联想(?q=&limit=);q 为空返回热门搜索 鉴权:appKey(可选接口);适用场景:员工福利购物 / 企业采购 可选。输入框联想:`q` 为已输入的前缀;`q` 为空时返回热门搜索词。搜索服务不可用时返回空列表(仍为 200),不影响主流程。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | q | string | 否 | 已输入的前缀;不传 = 热门搜索。最长 50 | | limit | integer | 否 | 默认 `10`。≥ 1 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].text | string | | | items[].type | string | query 热门搜索词 / category 类目 / brand 品牌。可选值:`query` / `category` / `brand` | | items[].hits | integer | 该词最近一次搜索的命中数(仅 query) | **响应示例** ```json { "items": [ { "text": "string", "type": "query", "hits": 0 } ] } ``` --- ### `POST /v1/enterprise/products/events` — 上报搜索结果上的点击 / 加购 / 下单(带回搜索返回的 searchId),帮助搜索排序 鉴权:appKey(可选接口);适用场景:员工福利购物 / 企业采购 可选。用户在搜索结果上点击、加购或下单时上报,带回搜索接口返回的 `searchId`,用于优化排序。尽力而为:搜索服务不可用时也返回成功。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | productId | string | 是 | | | event | string | 是 | 可选值:`click` / `cart` / `order` | | searchId | string | 否 | 搜索接口返回的 searchId。最长 64 | | position | integer | 否 | 在搜索结果里的位置(从 1 起)。≥ 1 | **请求示例**(只含必填字段) ```json { "productId": "string", "event": "click" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | **响应示例** ```json { "ok": true } ``` **错误** - 400:`BAD_REQUEST`:productId 缺失或 event 不是 click / cart / order --- ### `GET /v1/lm/products/{id}` — 商品详情(含 SKU,下单每行都要带 skuId) 鉴权:appKey;适用场景:消费者购物 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | id | string | 商品 ID,下单时原样放进 items[].productId | | externalItemId | string | | | title | string | | | subtitle | string | | | imageUrl | string | | | imageUrls | string[] | | | category | string | | | brand | string | | | price | number | 售价(元);多规格商品为最低规格价 | | marketPrice | number | | | shopName | string | | | sales30d | number | | | availability | string | 可选值:`in_stock` / `out_of_stock` | | featured | boolean | 是否运营精选 | | matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | matchedSku.skuId | string | | | matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | detailImages | string[] | | | specs | object | | | skus | object[] | | | skus[].skuId | string | 下单每行必带 | | skus[].specs | object | | | skus[].price | number | | | skus[].stock | number | 0 = 售罄;-1 = 上游不提供库存 | | skus[].image | string | | | skus[].canSell | boolean | false = 不可售 | **响应示例** ```json { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [ "string" ], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": { "skuId": "string", "specText": "string", "price": 0, "imageUrl": "string" }, "detailImages": [ "string" ], "specs": null, "skus": [ { "skuId": "string", "specs": null, "price": 0, "stock": 0, "image": "string", "canSell": true } ] } ``` **错误** - 404:`NOT_FOUND`:商品不存在或已下架 --- ### `POST /v1/lm/products/search` — 搜索 / 按条件浏览:商品 + 推荐规格,可附符合程度(mode=strict 只要完全符合的) 鉴权:appKey;适用场景:消费者购物 请求体带 version: 2(响应同样带 version: 2);不带 version 为旧版接口,返回格式不同,保留一个版本周期。按关键词 / 编码找商品,或按条件浏览。每条结果是「商品 + 推荐规格」,可附上符合程度与每个条件的判定(include: ["match"])。mode 控制多严:缺省 balanced(完全符合的在前、一件都没有才放宽);AI 助手推荐、清单解析建议 strict(只要完全符合的)。翻页用 nextCursor。匹配与排序规则、各商品池可用的筛选字段见开发者文档 §11。未带 x-open-user 时带 query、筛选或排序都返回 401 NEED_LOGIN,纯浏览只给第一页。 **请求体(application/json,必须带 version: 2,其余全部可选;不传 query = 按条件浏览。不认识的参数一律 400 并在 field 里指明(带了旧参数会提示新写法)。不带 version 的请求按旧版接口处理(keyword / category / brand / priceMin / priceMax / inStockOnly / sortBy / page / pageSize,返回旧的 { items, page, pageSize, total }),保留一个版本周期)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | version | integer | 是 | 接口版本,固定传 2。不传 = 旧版接口(返回格式不同)。可选值:`2` | | query | object | 否 | 找什么:text 与 code 二选一 | | query.text | string | 否 | 关键词。多个条件用空格分开,必须条件全部满足才算完全符合。最长 100 | | query.optional | string[] | 否 | text 里「有更好、没有也行」的词(如用户说颜色无所谓):只参与排序,不作为必须条件。必须是 text 里出现过的词,否则 400。最多 10 项 | | query.code | string | 否 | 按 SKU 编码 / 型号 / 条码 / 上游商品 ID 精确查,不容错、不改写。最长 64 | | filter | object | 否 | 硬条件:不满足就不返回 | | filter.category | string \| string[] | 否 | 叶子类目名,精确匹配;数组 = 任一 | | filter.brand | string \| string[] | 否 | 品牌名,精确匹配;数组 = 任一 | | filter.price | object | 否 | 价格区间(元,含边界),按规格价:任一可售规格落在区间内即命中,此时推荐的就是区间内的规格。传反了自动对调 | | filter.price.gte | number | 否 | ≥ 0 | | filter.price.lte | number | 否 | ≥ 0 | | filter.inStock | boolean | 否 | 只要有货的 | | unknown | string | 否 | 筛选字段没有值的商品怎么处理(当前可用字段都有值,预留)。可选值:`include` / `exclude`。默认 `"include"` | | mode | string | 否 | 多严。balanced:完全符合的在前、部分符合的随后,一件都没有时才放宽(返回 relaxation);strict:只要完全符合的,宁缺毋滥(AI 助手推荐、清单解析用);broad:全部给,含放宽得到的。可选值:`balanced` / `strict` / `broad`。默认 `"balanced"` | | sort | string | 否 | 顺序。价格按推荐规格的价格;任何排序下不符合的(related)都排在最后。可选值:`relevance` / `price_asc` / `price_desc` / `sales_desc`。默认 `"relevance"` | | profile | string | 否 | 排序预设:agent 推荐给人看的少量结果(符合程度优先,其次有货);mall 搜索结果页。可选值:`agent` / `mall`。默认 `"agent"` | | prefer | object[] | 否 | 软偏好:只影响同一符合程度内的先后,不影响返回哪些;多条按先后递减。sort 不是 relevance 时忽略。每条是以下三种写法之一:`{ "field": "price", "direction": "low" \| "high" }` 便宜 / 贵的优先;`{ "field": "brand", "value": "膳魔师" }` 这个品牌优先;`{ "text": "大容量" }` 这个词命中的优先。最多 5 项 | | excludeFields | string[] | 否 | 这次查询不用这些字段(只对 query.text 起作用):既不在里面找商品,也不拿它判断符合与否。用来对比某个字段的作用,如去掉卖点 sellingPoints。不能全部去掉。可选字段:title(标题)、titleGrams(标题按每两个字切开(中文分词切错时的兜底))、aliases(买家叫法(别名))、subtitle(副标题)、brand(品牌)、category(叶子类目名)、categoryPath(类目整条路径)、tags(平台类目路径)、skuSpecValues(各规格的规格值(颜色、尺码、容量、型号…)与材质)、skuTitles(各规格的规格名)、specsText(商品参数(前 600 字))、qualityPerformance(品质性能(前 300 字))、useCases(适用场景)、descriptionSellingPoints(商品描述与卖点(前 300 字))、audience(适用人群)、exactCodes(编码:上游商品 ID、SKU 编码、型号、条码)、supplierName(供应商名)。可选值:`title` / `titleGrams` / `aliases` / `subtitle` / `brand` / `category` / `categoryPath` / `tags` / `skuSpecValues` / `skuTitles` / `specsText` / `qualityPerformance` / `useCases` / `descriptionSellingPoints` / `audience` / `exactCodes` / `supplierName` | | limit | integer | 否 | 默认 `20`。≥ 1,≤ 50 | | cursor | string | 否 | 翻页:上次返回的 nextCursor。与本次请求的条件绑定(换了条件 400),1 小时有效 | | include | string[] | 否 | match:每条结果附上条件判定(符合程度、每个条件满足与否及凭据)。可选值:`match` | **请求示例**(只含必填字段) ```json { "version": 2 } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | version | integer | 响应版本,固定 2。解析前可以校验它,防止拿旧格式硬解析。可选值:`2` | | searchId | string | 带 query 时返回;上报点击 / 加购 / 下单时带回 | | interpretation | object | 带 query.text 时返回:我们怎么理解这次查询(供参考,不是约定) | | interpretation.searched | string | 纠错 / 改写后实际搜的词;与输入不同时可提示「已为您搜索 xx」 | | interpretation.requirements | object[] | | | interpretation.requirements[].text | string | | | interpretation.requirements[].role | string | product 品类 / attribute 属性 / brand 品牌 / other 其他(编码)。可选值:`product` / `attribute` / `brand` / `other` | | interpretation.requirements[].enforced | boolean | 是否作为必须条件(决定完全符合与否)。只有有把握的条件才是 true | | interpretation.requirements[].why | string | 不作为必须条件的原因:调用方标了可选 / 模糊词(大容量、好用)/ 认不出。可选值:`optional` / `vague` / `unrecognized` | | hits | object[] | | | hits[].product | object | | | hits[].product.id | string | 商品 ID,下单时原样放进 items[].productId | | hits[].product.externalItemId | string | | | hits[].product.title | string | | | hits[].product.subtitle | string | | | hits[].product.imageUrl | string | | | hits[].product.imageUrls | string[] | | | hits[].product.category | string | | | hits[].product.brand | string | | | hits[].product.price | number | 售价(元);多规格商品为最低规格价 | | hits[].product.marketPrice | number | | | hits[].product.shopName | string | | | hits[].product.sales30d | number | | | hits[].product.availability | string | 可选值:`in_stock` / `out_of_stock` | | hits[].product.featured | boolean | 是否运营精选 | | hits[].product.matchedSku | object | 关键词搜索命中的规格:多规格商品、且搜索词能对应到某个规格时才有(「黑色 1000ml 保温杯」→ 黑色 / 1000ml)。带价格区间时给区间内的规格。建议卡片直接展示该规格,点进详情时用 skuId 预先选中。没有 = 按商品展示 | | hits[].product.matchedSku.skuId | string | | | hits[].product.matchedSku.specText | string | 规格值,按「 / 」连接,如「黑色 / 1000ml」 | | hits[].product.matchedSku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径;缺省 = 用商品价 | | hits[].product.matchedSku.imageUrl | string | 该规格的图片;缺省 = 用商品主图 | | hits[].product.categoryId | string | 叶子类目 id(仅企业购) | | hits[].sku | object | 推荐的规格;商品没有可售规格时为 null | | hits[].sku.id | string | 规格 ID,即详情接口的 skus[].skuId;单规格商品(详情里没有规格选择)不给 | | hits[].sku.specText | string | 规格值,如「曜石黑 / 1000ml」 | | hits[].sku.specs | object | 规格名 → 规格值 | | hits[].sku.price | number | 该规格的对外售价(元),与详情接口的规格价同口径 | | hits[].sku.marketPrice | number | | | hits[].sku.imageUrl | string | 规格图;没有时用商品主图 | | hits[].sku.stock | integer | | | hits[].sku.available | boolean | | | hits[].sku.chosenBy | string | match 按搜索条件选出 / cheapest 条件在规格间没有区分,给价格区间内最便宜的 / only 只有一个规格。可选值:`match` / `cheapest` / `only` | | hits[].skuCount | integer | 可售规格数 | | hits[].match | object | include 含 match 时返回 | | hits[].match.level | string | exact 推荐的这个规格满足全部必须条件 / partial 没有不满足的,但有判断不了或分散在不同规格上的 / related 有不满足的,或是放宽得到的。可选值:`exact` / `partial` / `related` | | hits[].match.requirements | object[] | 每个条件在推荐规格上的判定,顺序同 interpretation.requirements | | hits[].match.requirements[].text | string | | | hits[].match.requirements[].state | string | met 满足 / unmet 不满足(如类目明确是别的品类)/ unknown 判断不了(字面上没找到不算不满足)。可选值:`met` / `unmet` / `unknown` | | hits[].match.requirements[].by | string | 满足的凭据:命中的规格值原文,如「曜石黑」 | | relaxation | object | 返回了不符合(related)的结果时才有:哪些必须条件没有满足。可提示「没有找到同时满足…的商品,以下是相关商品」 | | relaxation.dropped | string[] | | | relaxHints | object[] | 完全符合的不足 limit 时:去掉某个必须条件能有几件完全符合的。AI 助手可据此问用户要不要放宽,再把那个词放进 query.optional 重搜 | | relaxHints[].drop | string | | | relaxHints[].exact | integer | | | total | object | | | total.value | integer | | | total.exact | boolean | false = 估算值 | | nextCursor | string | 下一页的游标;没有 = 没有下一页。未登录访客不返回 | | degraded | boolean | 搜索服务暂时不可用、退回查库:只按标题拆词匹配,没有 match 与推荐规格的条件判定 | **响应示例** ```json { "version": 2, "searchId": "string", "interpretation": { "searched": "string", "requirements": [ { "text": "string", "role": "product", "enforced": true, "why": "optional" } ] }, "hits": [ { "product": { "id": "string", "externalItemId": "string", "title": "string", "subtitle": "string", "imageUrl": "string", "imageUrls": [], "category": "string", "brand": "string", "price": 0, "marketPrice": 0, "shopName": "string", "sales30d": 0, "availability": "in_stock", "featured": true, "matchedSku": {}, "categoryId": "string" }, "sku": { "id": "string", "specText": "string", "specs": null, "price": 0, "marketPrice": 0, "imageUrl": "string", "stock": 0, "available": true, "chosenBy": "match" }, "skuCount": 0, "match": { "level": "exact", "requirements": [] } } ], "relaxation": { "dropped": [ "string" ] }, "relaxHints": [ { "drop": "string", "exact": 0 } ], "total": { "value": 0, "exact": true }, "nextCursor": "string", "degraded": true } ``` **错误** - 400:`BAD_REQUEST`:参数不合法(field 指明哪个参数;带了旧参数会提示新写法),version 不是 2,或 cursor 无效 / 过期 / 与本次条件不符 --- ### `GET /v1/lm/categories` — 类目列表(按商品数排序,作为搜索的 category 参数) 鉴权:appKey;适用场景:消费者购物 按商品数降序的类目名列表(不是树),用作搜索的 category 参数。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | limit | integer | 否 | 默认 `30`。≥ 1,≤ 100 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].category | string | | | items[].count | integer | | **响应示例** ```json { "items": [ { "category": "string", "count": 0 } ] } ``` ## 结算与下单 结算与下单都收内联商品与收货人,购物车与地址簿可以用平台的,也可以自己做。下单固定传 payWith: "auto",付款方式由平台按企业配置(全额扣员工额度,或员工在企业购收银台付现金:支付宝 / 微信 / 对公);扣款与建单在同一事务里,idempotencyKey 同键重试不会重复建单。要员工付现金时,结算预览返回 cash(金额与可选的支付方式 payTypes)。 ### `GET /v1/divisions` — 行政区划逐级查(省 → 市 → 区县 → 乡镇街道):收货地址的 province / city / area / street 用这里选出的名称 鉴权:appKey;适用场景:员工福利购物 / 企业采购 从 parent=1(全国)开始逐级下钻:省 → 市 → 区县(divisionCode)→ 乡镇街道(townDivisionCode)。与福利GO 小程序、网页商城的地址选择同一份数据。老路径 `/v1/lm/divisions` 仍可用,返回相同。企业购下单的 `receiver.province / city / area` 用这里选出的名称,乡镇街道名称放进 `receiver.street`;也可以把带区划码的地址存进地址簿,下单传 `addressId`。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | parent | string | 否 | 上一级区划码。默认 `"1"` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | items | object[] | | | items[].code | string | | | items[].name | string | | | items[].parentCode | string | | | items[].hasChildren | boolean | | | items[].level | integer | 2 省 / 3 市 / 4 区县 / 5 乡镇街道 | **响应示例** ```json { "ok": true, "items": [ { "code": "string", "name": "string", "parentCode": "string", "hasChildren": true, "level": 0 } ] } ``` --- ### `POST /v1/enterprise/checkout/render` — 结算预览:权威价、运费、库存、额度是否足够 鉴权:用户态;适用场景:员工福利购物 / 企业采购 权威价、库存与可售状态;员工已绑定企业时返回 `points`(额度是否足够)。不需要收货地址。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | items | object[] | 是 | | | items[].productId | string | 是 | 商品接口返回的 id | | items[].skuId | string | 否 | 商品详情 skus[].skuId;skuId 为 null 的商品不要传 | | items[].qty | integer | 否 | 默认 `1`。≥ 1 | | device | string | 否 | (员工付现金 · 网页 / H5)场景,决定 `cash.payTypes` 里有没有微信;缺省按 appKey 登记的端。可选值:`pc` / `mobile` | **请求示例**(只含必填字段) ```json { "items": [ { "productId": "string" } ] } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | render | object | | | render.totalFee | number | | | render.postFee | number | | | render.payable | number | | | render.lines | object[] | | | items | object[] | | | items[].productId | string | | | items[].title | string | | | items[].imageUrl | string | | | items[].skuId | string | | | items[].skuText | string | | | items[].price | number | | | items[].qty | integer | | | items[].lineTotal | number | | | availabilityOk | boolean | | | issues | object[] | | | issues[].productId | string | | | issues[].title | string | | | issues[].reason | string | 可选值:`OFF_SHELF` / `OUT_OF_STOCK` / `PRICE_CHANGED` | | issues[].detail | string | | | points | object | 员工已绑定企业时返回 | | points.required | number | 这单需要的额度(100 = 1 元) | | points.balance | number | | | points.sufficient | boolean | | | points.canUsePoints | boolean | | | cash | object | 这单要员工付现金时返回(企业配置为全额现金或混合,且当前端已开通)。全额现金时 `cent` 就是应付总额;混合时 `points.required` 是企业承担的那部分 | | cash.cent | integer | 员工自付的现金(分) | | cash.ratioBp | integer | 企业承担比例(万分比);0 = 全额由员工付。混合支付暂未开放,目前恒为 0 | | cash.payTypes | string[] | 这个 appKey 在当前场景下可用的现金支付方式(支付宝 / 微信 / 对公),按它在你的下单页展示,员工选中的作为下单的 `payType` 传回。可选值:`ALIPAY` / `WECHAT_H5` / `DGZF` | **响应示例** ```json { "ok": true, "render": { "totalFee": 0, "postFee": 0, "payable": 0, "lines": [ null ] }, "items": [ { "productId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0 } ], "availabilityOk": true, "issues": [ { "productId": "string", "title": "string", "reason": "OFF_SHELF", "detail": "string" } ], "points": { "required": 0, "balance": 0, "sufficient": true, "canUsePoints": true }, "cash": { "cent": 0, "ratioBp": 0, "payTypes": [ "ALIPAY" ] } } ``` **错误** - 400:`EMPTY` / `PRODUCT_NOT_FOUND` / `RENDER_FAILED` / `ORG_EGP_NOT_READY`(企业的交易尚未开通) --- ### `POST /v1/enterprise/orders` — 下单(payWith: auto,付款方式按企业配置;要员工付现金时返回付款链接 launchUrl) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 **`payWith` 固定传 `"auto"`**:付款方式完全由平台按企业配置决定——全额扣员工额度、全额由员工付现金,还是按比例混合(**混合暂未开放**,开放后无需改接入);该 appKey 没开通员工付现金时一律扣额度。扣额度与建单在同一事务里。 要员工付现金时响应带 `launchUrl`(24 小时有效)——支付方式(`payType`)由你在下单页让员工选(可选项见结算预览的 `cash.payTypes`),会产生现金时必填;把员工带到 `launchUrl` 即进入付款(对公为转账信息)。发起后默认沿用这种方式,可在继续支付时更换。付完平台核实到账、扣额度、结清订单(付款页由企业购提供,不一定跳回你的页面;以订单详情的 `mixedPay.status` 与 `order.status` 推送为准)。员工付现金需要该 appKey 已开通(找平台在访问管理里开)。过期或中途关闭了用 `POST /v1/enterprise/orders/{bizOrderId}` `action=resume-pay` 重新取链接;结果以订单详情的 `mixedPay.status` 与 `order.status` 推送为准。 收货地址 `receiver` 与 `addressId`(地址簿)二选一,同时传以 addressId 为准。 **幂等**:强烈建议传 `idempotencyKey`,响应丢失时用同一个 key 重试,返回同一张单;不传时服务端按内容生成,只在 2 分钟内去重。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | items | object[] | 是 | | | items[].productId | string | 是 | 商品接口返回的 id | | items[].skuId | string | 否 | 商品详情 skus[].skuId;skuId 为 null 的商品不要传 | | items[].qty | integer | 否 | 默认 `1`。≥ 1 | | receiver | object | 否 | 收货人。省、市、区用名称(不是区划码),全部必填;名称请用 `GET /v1/divisions` 逐级选(乡镇街道放 `street`),叫法不一致上游会以 `321000 地址没有找到` 拒单 | | receiver.name | string | 是 | | | receiver.mobile | string | 是 | | | receiver.province | string | 是 | 省名称,取自 /v1/divisions。例:`浙江省` | | receiver.city | string | 是 | 市名称,取自 /v1/divisions。例:`杭州市` | | receiver.area | string | 是 | 区 / 县名称,取自 /v1/divisions。例:`西湖区` | | receiver.street | string | 否 | 乡镇街道名称(/v1/divisions 第四级),建议传:会拼在详细地址前面,地址更容易被上游认出 | | receiver.addressDetail | string | 是 | | | addressId | string | 否 | | | payWith | string | 否 | 固定传 `auto`:付款方式由平台按企业配置——全额扣员工额度、全额由员工在企业购收银台付现金,或两者按比例混合(混合暂未开放);appKey 没开通员工付现金时扣额度。可选值:`auto` | | payType | string | 否 | (员工付现金时)现金的支付方式:支付宝 / 微信 / 对公。**这单会产生现金时必填**(不传 400 `PAY_TYPE_REQUIRED`,响应带可选的 `payTypes`)。请在你的下单页按结算预览返回的 `cash.payTypes` 让员工选。必须在该 appKey 允许的范围内(平台在访问管理配置;没配时按登记的端:支付宝小程序为支付宝 + 对公,微信小程序为微信 + 对公,网页为全部、电脑上不含微信),否则 400 `PAY_TYPE_NOT_ALLOWED`。可选值:`ALIPAY` / `WECHAT_H5` / `DGZF` | | returnUrl | string | 否 | (员工付现金 · 网页 / H5)收银台与结果页的「返回」地址:须 https,且是该 appKey 登记的回调地址的域名或其子域。会追加 `bizOrderId` 与 `result`(success / pending / failed / cancel,只是提示)。现金在企业购收银台付,付完不一定跳回这里——以订单查询或 order.status 推送为准 | | device | string | 否 | (员工付现金 · 网页 / H5)收银台形态;缺省按 appKey 登记的端。可选值:`pc` / `mobile` | | idempotencyKey | string | 否 | 建议用你系统的订单号 | | remark | string | 否 | | **请求示例**(只含必填字段) ```json { "items": [ { "productId": "string" } ] } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | bizOrderId | string | | | order | object | | | order.bizOrderId | string | 订单号 | | order.outOrderId | string | | | order.unifiedStatus | string | 归一化订单状态,按它做业务判断。可选值:`CREATED` / `PAID` / `SHIPPED` / `DELIVERED` / `COMPLETED` / `CANCELED` / `REFUNDING` / `REFUNDED` / `REFUND_REJECTED` | | order.unifiedStatusLabel | string | | | order.displayStatus | string | | | order.totalFee | number | | | order.postFee | number | | | order.payable | number | | | order.items | object[] | | | order.items[].productId | string | | | order.items[].title | string | | | order.items[].imageUrl | string | | | order.items[].skuId | string | | | order.items[].skuText | string | | | order.items[].price | number | | | order.items[].qty | integer | | | order.items[].lineTotal | number | | | order.subOrders | object[] | 子订单;售后按子订单发起 | | order.subOrders[].bizOrderId | string | 子订单号 | | order.subOrders[].itemId | string | | | order.subOrders[].skuId | string | | | order.subOrders[].itemName | string | | | order.subOrders[].itemPrice | number | | | order.subOrders[].buyAmount | number | | | order.receiver | object | | | order.remark | string | | | order.createdAt | string | | | order.updatedAt | string | | | pointsCharged | number | 扣除的额度(100 = 1 元)。要员工付现金的单付完才扣,下单时不返回 | | hybrid | boolean | 这单要员工付现金(字段名沿用旧称) | | cashCent | integer | 员工要付的现金(分) | | launchUrl | string | 付款链接(企业购收银台入口),24 小时有效 | **响应示例** ```json { "ok": true, "bizOrderId": "string", "order": { "bizOrderId": "string", "outOrderId": "string", "unifiedStatus": "CREATED", "unifiedStatusLabel": "string", "displayStatus": "string", "totalFee": 0, "postFee": 0, "payable": 0, "items": [ { "productId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0 } ], "subOrders": [ { "bizOrderId": "string", "itemId": "string", "skuId": "string", "itemName": "string", "itemPrice": 0, "buyAmount": 0 } ], "receiver": null, "remark": "string", "createdAt": "string", "updatedAt": "string" }, "pointsCharged": 0, "hybrid": true, "cashCent": 0, "launchUrl": "string" } ``` **错误** - 400:`EMPTY` / `BAD_RECEIVER` / `ADDRESS_NOT_FOUND` / `PRODUCT_NOT_FOUND` / `UNAVAILABLE` / `INSUFFICIENT_POINTS` / `POINTS_NOT_BOUND` / `ORG_NOT_ACTIVE` / `MEMBER_NOT_ACTIVE` / `ORG_EGP_NOT_READY` / `IN_PROGRESS`(同 key 正在处理)/ `CREATE_FAILED` / `CREATE_PENDING`;员工付现金:`BAD_RETURN_URL` / `PAY_TYPE_REQUIRED`(会产生现金但没传 payType,响应带 `payTypes`)/ `PAY_TYPE_NOT_ALLOWED`(payType 不在该 appKey 的范围内)等 --- ### `GET /v1/enterprise/orders` — 订单列表 鉴权:用户态;适用场景:员工福利购物 / 企业采购 当前员工的订单,新的在前。要员工付现金的订单带 `mixedPay` 摘要(不含收银台链接,继续支付请进详情或调 resume-pay)。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | limit | integer | 否 | 默认 `50`。≥ 1,≤ 200 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].bizOrderId | string | 订单号 | | items[].outOrderId | string | | | items[].unifiedStatus | string | 归一化订单状态,按它做业务判断。可选值:`CREATED` / `PAID` / `SHIPPED` / `DELIVERED` / `COMPLETED` / `CANCELED` / `REFUNDING` / `REFUNDED` / `REFUND_REJECTED` | | items[].unifiedStatusLabel | string | | | items[].displayStatus | string | | | items[].totalFee | number | | | items[].postFee | number | | | items[].payable | number | | | items[].items | object[] | | | items[].items[].productId | string | | | items[].items[].title | string | | | items[].items[].imageUrl | string | | | items[].items[].skuId | string | | | items[].items[].skuText | string | | | items[].items[].price | number | | | items[].items[].qty | integer | | | items[].items[].lineTotal | number | | | items[].subOrders | object[] | 子订单;售后按子订单发起 | | items[].subOrders[].bizOrderId | string | 子订单号 | | items[].subOrders[].itemId | string | | | items[].subOrders[].skuId | string | | | items[].subOrders[].itemName | string | | | items[].subOrders[].itemPrice | number | | | items[].subOrders[].buyAmount | number | | | items[].receiver | object | | | items[].remark | string | | | items[].createdAt | string | | | items[].updatedAt | string | | **响应示例** ```json { "items": [ { "bizOrderId": "string", "outOrderId": "string", "unifiedStatus": "CREATED", "unifiedStatusLabel": "string", "displayStatus": "string", "totalFee": 0, "postFee": 0, "payable": 0, "items": [ {} ], "subOrders": [ {} ], "receiver": null, "remark": "string", "createdAt": "string", "updatedAt": "string" } ] } ``` --- ### `GET/POST /v1/enterprise/orders/{bizOrderId}` — 订单详情(要员工付现金的单带 mixedPay)/ 确认收货、取消、继续支付(action=resume-pay) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 #### GET:订单详情 要员工付现金的订单带 `mixedPay`;还没付完时给出 `mixedPay.launchUrl`。可用 `returnUrl` / `device` 覆盖下单时的设置。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | bizOrderId | string | 是 | | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | returnUrl | string | 否 | (员工付现金 · 网页 / H5)收银台与结果页的「返回」地址:须 https,且是该 appKey 登记的回调地址的域名或其子域。会追加 `bizOrderId` 与 `result`(success / pending / failed / cancel,只是提示)。现金在企业购收银台付,付完不一定跳回这里——以订单查询或 order.status 推送为准 | | device | string | 否 | (员工付现金 · 网页 / H5)收银台形态;缺省按 appKey 登记的端。可选值:`pc` / `mobile` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bizOrderId | string | 订单号 | | outOrderId | string | | | unifiedStatus | string | 归一化订单状态,按它做业务判断。可选值:`CREATED` / `PAID` / `SHIPPED` / `DELIVERED` / `COMPLETED` / `CANCELED` / `REFUNDING` / `REFUNDED` / `REFUND_REJECTED` | | unifiedStatusLabel | string | | | displayStatus | string | | | totalFee | number | | | postFee | number | | | payable | number | | | items | object[] | | | items[].productId | string | | | items[].title | string | | | items[].imageUrl | string | | | items[].skuId | string | | | items[].skuText | string | | | items[].price | number | | | items[].qty | integer | | | items[].lineTotal | number | | | subOrders | object[] | 子订单;售后按子订单发起 | | subOrders[].bizOrderId | string | 子订单号 | | subOrders[].itemId | string | | | subOrders[].skuId | string | | | subOrders[].itemName | string | | | subOrders[].itemPrice | number | | | subOrders[].buyAmount | number | | | receiver | object | | | remark | string | | | createdAt | string | | | updatedAt | string | | | mixedPay | object | 员工付现金的状态(只有要员工付现金的订单才有,字段名沿用旧称)。pending = 现金还没付;paid = 现金已到账、正在结清;confirmed = 已付清;failed = 订单已关(已付的现金原路退回) | | mixedPay.status | string | 可选值:`pending` / `paid` / `confirmed` / `failed` | | mixedPay.cashCent | integer | 员工自付的现金(分) | | mixedPay.pointsCent | integer | 企业承担的额度(100 = 1 元) | | mixedPay.launchUrl | string | (仅详情)收银台链接,24 小时有效;还没付完时给出 | **响应示例** ```json { "bizOrderId": "string", "outOrderId": "string", "unifiedStatus": "CREATED", "unifiedStatusLabel": "string", "displayStatus": "string", "totalFee": 0, "postFee": 0, "payable": 0, "items": [ { "productId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0 } ], "subOrders": [ { "bizOrderId": "string", "itemId": "string", "skuId": "string", "itemName": "string", "itemPrice": 0, "buyAmount": 0 } ], "receiver": null, "remark": "string", "createdAt": "string", "updatedAt": "string", "mixedPay": { "status": "pending", "cashCent": 0, "pointsCent": 0, "launchUrl": "string" } } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### POST:取消 / 确认收货 / 继续支付 `action` 放在 query 或 body:`cancel` 取消(已发货不能取消)、`receive` 确认收货、`resume-pay` 继续付现金(重新取付款链接)。失败返回 400 `{ ok: false, message }`。 `resume-pay`:现金已付完的直接结清,返回 `state: "done"`;还没付的返回 `state: "need_pay"` 与新的 `launchUrl`(同一张单,不会重复收钱)。可带 `returnUrl` / `device` / `payType`(已发起过的单沿用原支付方式,传别的不生效)。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | bizOrderId | string | 是 | | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`cancel` / `receive` / `resume-pay` | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`cancel` / `receive` / `resume-pay` | | payType | string | 否 | resume-pay:现金支付方式,须在 appKey 允许的范围内(同下单接口)。还没发起过付款的单必填(不传 400 `PAY_TYPE_REQUIRED`);已发起过的不传就沿用原方式。可选值:`ALIPAY` / `WECHAT_H5` / `DGZF` | | returnUrl | string | 否 | (员工付现金 · 网页 / H5)收银台与结果页的「返回」地址:须 https,且是该 appKey 登记的回调地址的域名或其子域。会追加 `bizOrderId` 与 `result`(success / pending / failed / cancel,只是提示)。现金在企业购收银台付,付完不一定跳回这里——以订单查询或 order.status 推送为准 | | device | string | 否 | (员工付现金 · 网页 / H5)收银台形态;缺省按 appKey 登记的端。可选值:`pc` / `mobile` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | message | string | | | state | string | resume-pay 才有。可选值:`done` / `need_pay` | | launchUrl | string | resume-pay 且 need_pay 时给出,24 小时有效 | | cashCent | integer | | **响应示例** ```json { "ok": true, "message": "string", "state": "done", "launchUrl": "string", "cashCent": 0 } ``` **错误** - 400:操作不允许,见 message;resume-pay 还可能是 `BAD_RETURN_URL` / `PAY_TYPE_NOT_ALLOWED` --- ### `GET /v1/enterprise/orders/{bizOrderId}/logistics` — 物流轨迹 鉴权:用户态;适用场景:员工福利购物 / 企业采购 一单可能分多个包裹。未发货时 `shipped: false`、packages 为空。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | bizOrderId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | bizOrderId | string | | | shipped | boolean | | | packages | object[] | | | packages[].packageId | string | | | packages[].logisticsCompany | string | | | packages[].invoiceNo | string | 运单号 | | packages[].statusDesc | string | | | packages[].consignTime | string | | | packages[].deliveredTime | string | | | packages[].items | object[] | | | packages[].items[].itemName | string | | | packages[].items[].skuName | string | | | packages[].items[].quantity | integer | | | packages[].tracks | object[] | | | packages[].tracks[].time | string | | | packages[].tracks[].desc | string | | | packages[].tracks[].city | string | | **响应示例** ```json { "bizOrderId": "string", "shipped": true, "packages": [ { "packageId": "string", "logisticsCompany": "string", "invoiceNo": "string", "statusDesc": "string", "consignTime": "string", "deliveredTime": "string", "items": [ {} ], "tracks": [ {} ] } ] } ``` **错误** - 400:`UPSTREAM`:上游查询失败 - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `GET /v1/enterprise/orders/in-transit` — 在路上的订单与最新物流节点(最近 3 单) 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 「我的」页「N 个订单正在路上」:`count` 为在途订单数(在最近 50 单里统计),`items` 只给最近 3 单及各自最新物流节点(节点缓存 60 秒)。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | count | integer | | | items | object[] | 最多 3 项 | | items[].bizOrderId | string | | | items[].unifiedStatus | string | | | items[].unifiedStatusLabel | string | | | items[].title | string | 第一件商品的标题 | | items[].imageUrl | string | | | items[].latest | object | 最新物流节点;查不到为 null。可能为 null | | items[].latest.desc | string | | | items[].latest.time | string | | **响应示例** ```json { "count": 0, "items": [ { "bizOrderId": "string", "unifiedStatus": "string", "unifiedStatusLabel": "string", "title": "string", "imageUrl": "string", "latest": { "desc": "string", "time": "string" } } ] } ``` --- ### `GET/DELETE /v1/enterprise/cart` — 购物车(含合计与额度是否够)/ 清空 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 #### GET:购物车 可选。服务端购物车,按员工保存、换设备不丢。合计只统计还能买的行。员工已绑定企业时带 `points`:这车需要多少额度、够不够(企业为 active 且余额足够才为 true)。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].productId | string | | | items[].externalItemId | string | | | items[].title | string | | | items[].imageUrl | string | | | items[].skuId | string | | | items[].skuText | string | 规格文案,如「黑色 / L」 | | items[].price | number | | | items[].qty | integer | | | items[].lineTotal | number | | | items[].available | boolean | 缺省 = 能买;加购后下架、不可售、售罄时为 false | | items[].unavailableReason | string | 不能买的原因,可直接展示 | | totalQty | integer | 只统计还能买的行 | | totalAmount | number | 元;只统计还能买的行 | | points | object | 员工已绑定企业时返回 | | points.required | number | 需要的额度(100 = 1 元) | | points.balance | number | | | points.sufficient | boolean | | **响应示例** ```json { "items": [ { "productId": "string", "externalItemId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0, "available": true, "unavailableReason": "string" } ], "totalQty": 0, "totalAmount": 0, "points": { "required": 0, "balance": 0, "sufficient": true } } ``` #### DELETE:清空购物车 可选。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` --- ### `POST/PUT/DELETE /v1/enterprise/cart/items` — 加购(累加)/ 设数量 / 移出(DELETE ?productId=&skuId=) 鉴权:用户态(可选接口);适用场景:员工福利购物 / 企业采购 #### POST:加入购物车 可选。同一商品 + SKU 已在车里时数量累加。`qty` 缺省 1。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | productId | string | 是 | | | skuId | string | 否 | 商品详情 skus[].skuId;skuId 为 null 的商品不要传 | | qty | integer | 否 | ≥ 0 | **请求示例**(只含必填字段) ```json { "productId": "string" } ``` **返回字段(成功,返回最新购物车)** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | cart | object | | | cart.items | object[] | | | cart.items[].productId | string | | | cart.items[].externalItemId | string | | | cart.items[].title | string | | | cart.items[].imageUrl | string | | | cart.items[].skuId | string | | | cart.items[].skuText | string | 规格文案,如「黑色 / L」 | | cart.items[].price | number | | | cart.items[].qty | integer | | | cart.items[].lineTotal | number | | | cart.items[].available | boolean | 缺省 = 能买;加购后下架、不可售、售罄时为 false | | cart.items[].unavailableReason | string | 不能买的原因,可直接展示 | | cart.totalQty | integer | 只统计还能买的行 | | cart.totalAmount | number | 元;只统计还能买的行 | **响应示例** ```json { "ok": true, "cart": { "items": [ { "productId": "string", "externalItemId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0, "available": true, "unavailableReason": "string" } ], "totalQty": 0, "totalAmount": 0 } } ``` **错误** - 400:缺少 productId #### PUT:设置数量 可选。把该商品 + SKU 的数量**设为** `qty`;`qty` 为 0 即删除。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | productId | string | 是 | | | skuId | string | 否 | 商品详情 skus[].skuId;skuId 为 null 的商品不要传 | | qty | integer | 否 | ≥ 0 | **请求示例**(只含必填字段) ```json { "productId": "string" } ``` **返回字段(成功,返回最新购物车)** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | cart | object | | | cart.items | object[] | | | cart.items[].productId | string | | | cart.items[].externalItemId | string | | | cart.items[].title | string | | | cart.items[].imageUrl | string | | | cart.items[].skuId | string | | | cart.items[].skuText | string | 规格文案,如「黑色 / L」 | | cart.items[].price | number | | | cart.items[].qty | integer | | | cart.items[].lineTotal | number | | | cart.items[].available | boolean | 缺省 = 能买;加购后下架、不可售、售罄时为 false | | cart.items[].unavailableReason | string | 不能买的原因,可直接展示 | | cart.totalQty | integer | 只统计还能买的行 | | cart.totalAmount | number | 元;只统计还能买的行 | **响应示例** ```json { "ok": true, "cart": { "items": [ { "productId": "string", "externalItemId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0, "available": true, "unavailableReason": "string" } ], "totalQty": 0, "totalAmount": 0 } } ``` **错误** - 400:缺少 productId #### DELETE:移出购物车 可选。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | productId | string | 是 | | | skuId | string | 否 | | **返回字段(成功,返回最新购物车)** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | cart | object | | | cart.items | object[] | | | cart.items[].productId | string | | | cart.items[].externalItemId | string | | | cart.items[].title | string | | | cart.items[].imageUrl | string | | | cart.items[].skuId | string | | | cart.items[].skuText | string | 规格文案,如「黑色 / L」 | | cart.items[].price | number | | | cart.items[].qty | integer | | | cart.items[].lineTotal | number | | | cart.items[].available | boolean | 缺省 = 能买;加购后下架、不可售、售罄时为 false | | cart.items[].unavailableReason | string | 不能买的原因,可直接展示 | | cart.totalQty | integer | 只统计还能买的行 | | cart.totalAmount | number | 元;只统计还能买的行 | **响应示例** ```json { "ok": true, "cart": { "items": [ { "productId": "string", "externalItemId": "string", "title": "string", "imageUrl": "string", "skuId": "string", "skuText": "string", "price": 0, "qty": 0, "lineTotal": 0, "available": true, "unavailableReason": "string" } ], "totalQty": 0, "totalAmount": 0 } } ``` **错误** - 400:缺少 productId ## 售后与开票 售后按子订单发起,已发货的回传退货运单。企业购订单提交后自动开票,抬头取自注册时的企业信息。 ### `POST /v1/enterprise/refunds` — 发起售后 鉴权:用户态;适用场景:员工福利购物 / 企业采购 按子订单发起;一单多件时 `subOrderId` 必填(取自订单详情 subOrders)。退款金额退回员工额度。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | bizOrderId | string | 是 | | | subOrderId | string | 否 | | | reasonId | string | 否 | | | reasonText | string | 否 | | | amount | number | 否 | 退款金额(元),不传按可退全额 | | needReturn | boolean | 否 | 是否需要寄回商品 | **请求示例**(只含必填字段) ```json { "bizOrderId": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | refund | object | | | refund.refundId | string | | | refund.bizOrderId | string | | | refund.subOrderId | string | | | refund.status | integer | 0 已撤销 / 1–8 处理中到完成,展示用 statusLabel | | refund.statusLabel | string | | | refund.amount | number | | | refund.reason | string | | | refund.createdAt | string | | | subOrderId | string | | **响应示例** ```json { "ok": true, "refund": { "refundId": "string", "bizOrderId": "string", "subOrderId": "string", "status": 0, "statusLabel": "string", "amount": 0, "reason": "string", "createdAt": "string" }, "subOrderId": "string" } ``` **错误** - 400:`NOT_PAID` / `ORDER_CLOSED` / `SUB_ORDER_REQUIRED` / `SUB_ORDER_INVALID` / `REASON_INVALID` / `PROOF_REQUIRED` / `NO_REFUNDABLE_AMOUNT` / `SUBMIT_FAILED` / `NOT_FOUND` 等 --- ### `GET /v1/enterprise/refunds` — 售后列表 鉴权:用户态;适用场景:员工福利购物 / 企业采购 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | limit | integer | 否 | 默认 `50`。≥ 1,≤ 200 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].refundId | string | | | items[].bizOrderId | string | | | items[].subOrderId | string | | | items[].status | integer | 0 已撤销 / 1–8 处理中到完成,展示用 statusLabel | | items[].statusLabel | string | | | items[].amount | number | | | items[].reason | string | | | items[].createdAt | string | | **响应示例** ```json { "items": [ { "refundId": "string", "bizOrderId": "string", "subOrderId": "string", "status": 0, "statusLabel": "string", "amount": 0, "reason": "string", "createdAt": "string" } ] } ``` --- ### `GET/POST /v1/enterprise/refunds/{refundId}` — 售后详情 / 撤销、回传退货运单 鉴权:用户态;适用场景:员工福利购物 / 企业采购 #### GET:售后详情 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | refundId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | refundId | string | | | bizOrderId | string | | | subOrderId | string | | | status | integer | 0 已撤销 / 1–8 处理中到完成,展示用 statusLabel | | statusLabel | string | | | amount | number | | | reason | string | | | createdAt | string | | **响应示例** ```json { "refundId": "string", "bizOrderId": "string", "subOrderId": "string", "status": 0, "statusLabel": "string", "amount": 0, "reason": "string", "createdAt": "string" } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### POST:撤销售后 / 回传退货运单 `?action=cancel`(缺省)撤销;`?action=return` 寄回商品后回传运单。失败返回 400 `{ ok: false, message }`。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | refundId | string | 是 | | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`cancel` / `return`。默认 `"cancel"` | **请求体(application/json,仅 action=return 时需要)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | logisticsCompany | string | 否 | 快递公司编码或中文名 | | invoiceNo | string | 否 | 退货运单号 | | mobile | string | 否 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | message | string | | **响应示例** ```json { "ok": true, "message": "string" } ``` **错误** - 400:操作不允许,见 message --- ### `GET /v1/buyer/invoices` — 开票记录(状态、发票号、下载地址) 鉴权:用户态;适用场景:员工福利购物 / 企业采购 订单提交后自动开票,抬头取企业开户时的信息。最多返回最近 100 条。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | | | items[].purchaseOrderId | string | | | items[].title | string | | | items[].taxNo | string | | | items[].amount | string | | | items[].status | string | applied = 上游已受理;issued = 已开出。可选值:`pending` / `applied` / `issued` / `failed` / `rejected` | | items[].upstreamInvoiceNos | string[] | | | items[].fileUrl | string | 发票下载地址(issued 后) | | items[].upstreamError | string | failed 时上游给的原因 | | items[].createdAt | string | | **响应示例** ```json { "items": [ { "id": "string", "purchaseOrderId": "string", "title": "string", "taxNo": "string", "amount": "string", "status": "pending", "upstreamInvoiceNos": [ "string" ], "fileUrl": "string", "upstreamError": "string", "createdAt": "string" } ] } ``` ## 用户与收货地址 用户身份直接用你那边每个用户的 open-id(放进 x-open-user),首次访问自动建档,不需要先注册。收货地址要用行政区划码,先用区划接口级联选出来;地址簿是可选的便利,不用也能下单。 ### `GET /v1/divisions` — 行政区划级联(下单要的 divisionCode / townDivisionCode;老路径 /v1/lm/divisions 仍可用) 鉴权:appKey;适用场景:消费者购物 从 parent=1(全国)开始逐级下钻:省 → 市 → 区县(divisionCode)→ 乡镇街道(townDivisionCode)。与福利GO 小程序、网页商城的地址选择同一份数据。老路径 `/v1/lm/divisions` 仍可用,返回相同。企业购下单的 `receiver.province / city / area` 用这里选出的名称,乡镇街道名称放进 `receiver.street`;也可以把带区划码的地址存进地址簿,下单传 `addressId`。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | parent | string | 否 | 上一级区划码。默认 `"1"` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | items | object[] | | | items[].code | string | | | items[].name | string | | | items[].parentCode | string | | | items[].hasChildren | boolean | | | items[].level | integer | 2 省 / 3 市 / 4 区县 / 5 乡镇街道 | **响应示例** ```json { "ok": true, "items": [ { "code": "string", "name": "string", "parentCode": "string", "hasChildren": true, "level": 0 } ] } ``` --- ### `GET/POST /v1/buyer/addresses` — 地址簿列表 / 新增(complete 标记能否直接下单) 鉴权:用户态(可选接口);适用场景:消费者购物 #### GET:地址簿 可选:也可以不用地址簿,下单时直接传 receiver。默认地址在前。 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | | | items[].receiver | string | | | items[].receiverPhone | string | | | items[].province | string | | | items[].city | string | | | items[].district | string | | | items[].street | string | | | items[].divisionCode | string | | | items[].townDivisionCode | string | | | items[].addressDetail | string | | | items[].isDefault | boolean | | | items[].complete | boolean | 能否直接用于下单 | | items[].missingFields | string[] | 缺哪些项(如 divisionCode、townDivisionCode) | | items[].createdAt | string | | **响应示例** ```json { "items": [ { "id": "string", "receiver": "string", "receiverPhone": "string", "province": "string", "city": "string", "district": "string", "street": "string", "divisionCode": "string", "townDivisionCode": "string", "addressDetail": "string", "isDefault": true, "complete": true, "missingFields": [ "string" ], "createdAt": "string" } ] } ``` #### POST:新增地址 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | receiver | string | 是 | | | receiverPhone | string | 是 | | | addressDetail | string | 是 | | | province | string | 否 | | | city | string | 否 | | | district | string | 否 | | | street | string | 否 | | | divisionCode | string | 否 | 传了会自动补齐省市区名称 | | townDivisionCode | string | 否 | | | isDefault | boolean | 否 | | **请求示例**(只含必填字段) ```json { "receiver": "string", "receiverPhone": "string", "addressDetail": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | address | object | | | address.id | string | | | address.receiver | string | | | address.receiverPhone | string | | | address.province | string | | | address.city | string | | | address.district | string | | | address.street | string | | | address.divisionCode | string | | | address.townDivisionCode | string | | | address.addressDetail | string | | | address.isDefault | boolean | | | address.complete | boolean | 能否直接用于下单 | | address.missingFields | string[] | 缺哪些项(如 divisionCode、townDivisionCode) | | address.createdAt | string | | **响应示例** ```json { "ok": true, "address": { "id": "string", "receiver": "string", "receiverPhone": "string", "province": "string", "city": "string", "district": "string", "street": "string", "divisionCode": "string", "townDivisionCode": "string", "addressDetail": "string", "isDefault": true, "complete": true, "missingFields": [ "string" ], "createdAt": "string" } } ``` **错误** - 400:参数不合法 --- ### `PUT/POST/DELETE /v1/buyer/addresses/{id}` — 改 / 设默认 / 删地址 鉴权:用户态(可选接口);适用场景:消费者购物 #### PUT:修改地址 整体覆盖:没传的字段会被清空。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | receiver | string | 是 | | | receiverPhone | string | 是 | | | addressDetail | string | 是 | | | province | string | 否 | | | city | string | 否 | | | district | string | 否 | | | street | string | 否 | | | divisionCode | string | 否 | 传了会自动补齐省市区名称 | | townDivisionCode | string | 否 | | | isDefault | boolean | 否 | | **请求示例**(只含必填字段) ```json { "receiver": "string", "receiverPhone": "string", "addressDetail": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | address | object | | | address.id | string | | | address.receiver | string | | | address.receiverPhone | string | | | address.province | string | | | address.city | string | | | address.district | string | | | address.street | string | | | address.divisionCode | string | | | address.townDivisionCode | string | | | address.addressDetail | string | | | address.isDefault | boolean | | | address.complete | boolean | 能否直接用于下单 | | address.missingFields | string[] | 缺哪些项(如 divisionCode、townDivisionCode) | | address.createdAt | string | | **响应示例** ```json { "ok": true, "address": { "id": "string", "receiver": "string", "receiverPhone": "string", "province": "string", "city": "string", "district": "string", "street": "string", "divisionCode": "string", "townDivisionCode": "string", "addressDetail": "string", "isDefault": true, "complete": true, "missingFields": [ "string" ], "createdAt": "string" } } ``` **错误** - 400:参数不合法 #### POST:设为默认地址 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 是 | 固定为 default。可选值:`default` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### DELETE:删除地址 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | 例:`true` | **响应示例** ```json { "ok": true } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 ## 结算与订单 下单前用结算预览拿权威价、运费与可售状态。下单与付款走下面的「平台收银台」:用户付款后平台自动下单,建出的订单在这里查订单、物流、确认收货。 ### `POST /v1/lm/checkout/render` — 结算预览:权威价、运费、可售状态 鉴权:用户态;适用场景:消费者购物 按本地价计算,不需要地址。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | items | object[] | 是 | | | items[].productId | string | 是 | 商品接口返回的 id | | items[].skuId | string | 否 | 商品详情 skus[].skuId | | items[].qty | integer | 否 | 默认 `1`。≥ 1 | **请求示例**(只含必填字段) ```json { "items": [ { "productId": "string" } ] } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | render | object | | | render.totalFee | number | | | render.postFee | number | | | render.payable | number | | | render.lines | object[] | | | render.lines[].productId | string | | | render.lines[].skuId | string | | | render.lines[].itemName | string | | | render.lines[].itemPic | string | | | render.lines[].skuText | string | | | render.lines[].itemPrice | number | | | render.lines[].quantity | integer | | **响应示例** ```json { "ok": true, "render": { "totalFee": 0, "postFee": 0, "payable": 0, "lines": [ { "productId": "string", "skuId": "string", "itemName": "string", "itemPic": "string", "skuText": "string", "itemPrice": 0, "quantity": 0 } ] } } ``` **错误** - 400:`EMPTY` / `PRODUCT_NOT_FOUND` / `SKU_UNAVAILABLE` --- ### `GET /v1/lm/orders` — 订单列表 鉴权:用户态;适用场景:消费者购物 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | limit | integer | 否 | 默认 `50`。≥ 1,≤ 200 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].id | string | | | items[].outerPurchaseOrderId | string | = 你传的 idempotencyKey | | items[].purchaseOrderId | string | 上游采购单号;还在创建中时为空 | | items[].lmStatus | string | 可选值:`PENDING` / `CREATING` / `CREATED` / `FAILED` | | items[].displayStatus | string | | | items[].totalFee | number | | | items[].postFee | number | | | items[].payable | number | | | items[].items | object[] | | | items[].items[].productId | string | | | items[].items[].skuId | string | | | items[].items[].title | string | | | items[].items[].skuText | string | | | items[].items[].imageUrl | string | | | items[].items[].price | number | | | items[].items[].qty | integer | | | items[].items[].lineTotal | number | | | items[].receiver | object | | | items[].remark | string | | | items[].message | string | | | items[].createdAt | string | | | items[].orders | object[] | 子订单(详情接口返回)。确认收货、物流、售后都按子订单号 orderId | | items[].orders[].orderId | string | 子订单号 | | items[].orders[].orderStatus | string | 1 待支付 / 2 已支付 / 4 已退款关闭 / 6 交易成功 / 8 已关闭 | | items[].orders[].logisticsStatus | string | | | items[].orders[].refundStatus | string | | | items[].orders[].displayStatus | string | | | items[].orders[].orderAmount | number | | | items[].orders[].lines | object[] | | | items[].orders[].lines[].orderLineId | string | 订单行 id,售后用 | | items[].orders[].lines[].productId | string | | | items[].orders[].lines[].productTitle | string | | | items[].orders[].lines[].skuId | string | | | items[].orders[].lines[].skuTitle | string | | | items[].orders[].lines[].quantity | integer | | | items[].orders[].lines[].payFee | number | | | items[].orders[].closedReason | string | | | items[].orders[].createdAt | string | | **响应示例** ```json { "items": [ { "id": "string", "outerPurchaseOrderId": "string", "purchaseOrderId": "string", "lmStatus": "PENDING", "displayStatus": "string", "totalFee": 0, "postFee": 0, "payable": 0, "items": [ {} ], "receiver": null, "remark": "string", "message": "string", "createdAt": "string", "orders": [ {} ] } ] } ``` --- ### `GET/POST /v1/lm/orders/{id}` — 订单详情 / 确认收货 鉴权:用户态;适用场景:消费者购物 #### GET:订单详情 返回子订单 orders。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | 采购单 id、上游采购单号或你的 idempotencyKey 都可以 | **返回字段(采购单。一张采购单可能拆成多张子订单(orders))** | 字段 | 类型 | 说明 | |---|---|---| | id | string | | | outerPurchaseOrderId | string | = 你传的 idempotencyKey | | purchaseOrderId | string | 上游采购单号;还在创建中时为空 | | lmStatus | string | 可选值:`PENDING` / `CREATING` / `CREATED` / `FAILED` | | displayStatus | string | | | totalFee | number | | | postFee | number | | | payable | number | | | items | object[] | | | items[].productId | string | | | items[].skuId | string | | | items[].title | string | | | items[].skuText | string | | | items[].imageUrl | string | | | items[].price | number | | | items[].qty | integer | | | items[].lineTotal | number | | | receiver | object | | | remark | string | | | message | string | | | createdAt | string | | | orders | object[] | 子订单(详情接口返回)。确认收货、物流、售后都按子订单号 orderId | | orders[].orderId | string | 子订单号 | | orders[].orderStatus | string | 1 待支付 / 2 已支付 / 4 已退款关闭 / 6 交易成功 / 8 已关闭 | | orders[].logisticsStatus | string | | | orders[].refundStatus | string | | | orders[].displayStatus | string | | | orders[].orderAmount | number | | | orders[].lines | object[] | | | orders[].lines[].orderLineId | string | 订单行 id,售后用 | | orders[].lines[].productId | string | | | orders[].lines[].productTitle | string | | | orders[].lines[].skuId | string | | | orders[].lines[].skuTitle | string | | | orders[].lines[].quantity | integer | | | orders[].lines[].payFee | number | | | orders[].closedReason | string | | | orders[].createdAt | string | | **响应示例** ```json { "id": "string", "outerPurchaseOrderId": "string", "purchaseOrderId": "string", "lmStatus": "PENDING", "displayStatus": "string", "totalFee": 0, "postFee": 0, "payable": 0, "items": [ { "productId": "string", "skuId": "string", "title": "string", "skuText": "string", "imageUrl": "string", "price": 0, "qty": 0, "lineTotal": 0 } ], "receiver": null, "remark": "string", "message": "string", "createdAt": "string", "orders": [ { "orderId": "string", "orderStatus": "string", "logisticsStatus": "string", "refundStatus": "string", "displayStatus": "string", "orderAmount": 0, "lines": [ {} ], "closedReason": "string", "createdAt": "string" } ] } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### POST:确认收货 按子订单确认收货:`action=receive`,`orderId` 传子订单号(query 或 body)。失败返回 400 `{ ok: false, message }`。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | 采购单 id、上游采购单号或你的 idempotencyKey 都可以 | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`receive` | | orderId | string | 否 | 子订单号 | **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`receive` | | orderId | string | 否 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | message | string | | **响应示例** ```json { "ok": true, "message": "string" } ``` **错误** - 400:见 message --- ### `GET /v1/lm/orders/{id}/logistics` — 子订单物流轨迹 鉴权:用户态;适用场景:消费者购物 路径参数为**子订单号**。上游查询失败时仍返回 200,`success: false`。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | id | string | 是 | 子订单号 orderId | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | success | boolean | | | message | string | | | packages | object[] | | | packages[].mailNo | string | 运单号 | | packages[].companyName | string | | | packages[].goods | object[] | | | packages[].goods[].name | string | | | packages[].goods[].skuTitle | string | | | packages[].goods[].quantity | integer | | | packages[].traces | object[] | | | packages[].traces[].time | string | | | packages[].traces[].desc | string | | **响应示例** ```json { "success": true, "message": "string", "packages": [ { "mailNo": "string", "companyName": "string", "goods": [ {} ], "traces": [ {} ] } ] } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 ## 平台收银台 下单与付款:用户在浏览器里用支付宝付款,平台收到支付通知后自动下单,下单失败自动退款,你不用处理退款补偿。手上有完整收货地址就直接要支付链接;没有就给用户托管结账页,让他自己填。退款、退货也在这一组。 ### `POST /v1/lm/pay/web-prepare` — 下单并返回支付短链 payUrl 与它的二维码 qrImageUrl(需带收货地址;idempotencyKey 同键重放返回同一张收款单) 鉴权:用户态;适用场景:消费者购物 平台收款方式(手上有完整收货地址时):返回支付短链 `payUrl` 与它的二维码 `qrImageUrl`——在电脑上或对话里优先展示二维码,用户用手机支付宝扫码付款(手机上已登录),否则把 `payUrl` 交给用户打开付款;付款成功后平台自动下单,失败自动退款。同一 `idempotencyKey` 重放返回同一张收款单(`outTradeNo` 不变),内容不同则 409。链接自首次生成起约 23 小时内可付。付款结果以收款单查询为准。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | items | object[] | 是 | | | items[].productId | string | 是 | 商品接口返回的 id | | items[].skuId | string | 是 | 商品详情 skus[].skuId,必填 | | items[].qty | integer | 否 | 默认 `1`。≥ 1 | | receiver | object | 否 | 收货人。地区用行政区划码,先用 GET /v1/divisions 级联查出 | | receiver.receiver | string | 是 | 收货人姓名 | | receiver.receiverPhone | string | 是 | | | receiver.divisionCode | string | 是 | 区县级(四级)区划码,必填。例:`330106` | | receiver.townDivisionCode | string | 否 | 乡镇级(五级)区划码,强烈建议带上,缺了上游可能拒单。例:`330106001` | | receiver.addressDetail | string | 是 | | | addressId | string | 否 | 与 receiver 二选一,必须给其一 | | idempotencyKey | string | 是 | 你方订单唯一号(同一用户内唯一)。最长 128 | | device | string | 否 | 收银台类型。payUrl 为短链时打开它的设备会自动选择(手机 / 电脑),此参数可不传;未启用短链时决定网关地址的类型(缺省 pc)。可选值:`pc` / `mobile`。默认 `"pc"` | | returnUrl | string | 否 | https,域名须为登记的 callback_url 域名或其子域;不传则停在支付宝成功页 | | remark | string | 否 | | **请求示例**(只含必填字段) ```json { "items": [ { "productId": "string", "skuId": "string" } ], "idempotencyKey": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | outTradeNo | string | | | money | string | | | payUrl | string | 支付短链(约 60 字符)。打开时按设备生成支付宝收银台(手机 / 电脑),付完回跳 returnUrl;已付 / 已关 / 超时会给出提示页。手机上直接打开即可付款 | | qrImageUrl | string | payUrl 的二维码图片(PNG,几百字节),可直接放进对话或网页让用户用手机支付宝扫码;未配置公网地址时不返回,payUrl 也回落为支付宝网关地址 | **响应示例** ```json { "ok": true, "outTradeNo": "string", "money": "string", "payUrl": "string", "qrImageUrl": "string" } ``` **错误** - 400:`EMPTY` / `SKU_REQUIRED` / `PRODUCT_NOT_FOUND` / `SKU_UNAVAILABLE` / `BAD_RECEIVER` / `ADDRESS_NOT_FOUND` / `BAD_IDEMPOTENCY_KEY` / `BAD_DEVICE` / `BAD_RETURN_URL` / `PAY_EXPIRED` - 409:`IDEMPOTENCY_CONFLICT` / `ALREADY_PAID` / `PAY_CLOSED` / `IN_PROGRESS` - 503:`PAY_NOT_CONFIGURED` --- ### `POST /v1/lm/checkout/sessions` — 托管结账页:返回 checkoutUrl,用户在页面上核对、填地址后用支付宝付款(地址可不传;带 idempotencyKey 时同键重试返回同一个结账页) 鉴权:用户态;适用场景:消费者购物 平台收款方式(手上没有完整收货地址时):建结账会话,把 `checkoutUrl` 交给用户,用户在平台结账页核对商品、补地址,跳浏览器支付宝付款。付款成功后平台自动下单,失败自动退款。`checkoutUrl` 即付款凭据,只发给对应用户。地址可不传,由用户在页面填写。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | items | object[] | 是 | | | items[].productId | string | 是 | 商品接口返回的 id | | items[].skuId | string | 是 | 商品详情 skus[].skuId,必填 | | items[].qty | integer | 否 | 默认 `1`。≥ 1 | | receiver | object | 否 | 收货人。地区用行政区划码,先用 GET /v1/divisions 级联查出 | | receiver.receiver | string | 是 | 收货人姓名 | | receiver.receiverPhone | string | 是 | | | receiver.divisionCode | string | 是 | 区县级(四级)区划码,必填。例:`330106` | | receiver.townDivisionCode | string | 否 | 乡镇级(五级)区划码,强烈建议带上,缺了上游可能拒单。例:`330106001` | | receiver.addressDetail | string | 是 | | | idempotencyKey | string | 否 | 幂等键(建议必传,用你的订单号)。同键重试返回同一个结账页(新的 checkoutUrl,旧链接失效),不会出现两个都能付的页面;同键不同内容返回 409 IDEMPOTENCY_CONFLICT,已过期且未付返回 409 SESSION_EXPIRED。最长 128 | | addressId | string | 否 | | | returnUrl | string | 否 | 付完「返回应用」的地址;https,域名须为登记的 callback_url 域名或其子域 | | remark | string | 否 | | **请求示例**(只含必填字段) ```json { "items": [ { "productId": "string", "skuId": "string" } ] } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | sessionId | string | | | checkoutUrl | string | | | expiresAt | string(date-time) | | | money | string | | **响应示例** ```json { "ok": true, "sessionId": "string", "checkoutUrl": "string", "expiresAt": "2026-11-02T10:00:00+08:00", "money": "string" } ``` **错误** - 400:`EMPTY` / `SKU_REQUIRED` / `PRODUCT_NOT_FOUND` / `SKU_UNAVAILABLE` / `BAD_RECEIVER` / `ADDRESS_NOT_FOUND` / `BAD_RETURN_URL` - 503:`NOT_CONFIGURED` --- ### `GET /v1/lm/checkout/sessions/{sessionId}` — 结账会话进度(待支付 / 已过期 / 已发起支付 + 收款单状态) 鉴权:用户态;适用场景:消费者购物 `state`:open 待支付 / expired 未支付已过期 / paying 已发起支付(再看 `payStatus`,fulfilled 即已下单)。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | sessionId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | sessionId | string | | | state | string | 可选值:`open` / `expired` / `paying` | | outTradeNo | string | | | payStatus | string | | | purchaseOrderId | string | | | money | string | | **响应示例** ```json { "ok": true, "sessionId": "string", "state": "open", "outTradeNo": "string", "payStatus": "string", "purchaseOrderId": "string", "money": "string" } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `GET /v1/lm/pay/orders` — 收款单列表 鉴权:用户态;适用场景:消费者购物 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | limit | integer | 否 | 默认 `50`。≥ 1,≤ 200 | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].outTradeNo | string | 收款单号 | | items[].status | string | 可选值:`pending_payment` / `paid` / `fulfilling` / `fulfilled` / `refund_requested` / `awaiting_return` / `returning` / `refund_pending` / `manual_review` / `refunded` / `partially_refunded` / `refund_failed` / `closed` | | items[].gateway | string | 可选值:`alipay` / `wxpay` | | items[].tradeNo | string | | | items[].money | string | 金额(元) | | items[].name | string | | | items[].items | object[] | | | items[].receiver | object | | | items[].upstreamOrderId | string | 付款后平台自动下单得到的采购单号 | | items[].createdAt | string | | | items[].paidAt | string | 可能为 null | | items[].fulfilledAt | string | 可能为 null | | items[].refundedAt | string | 可能为 null | | items[].refundItems | object[] | 详情接口返回:按订单行的退款进度 | | items[].refundItems[].subOrderId | string | | | items[].refundItems[].amount | number | | | items[].refundItems[].status | string | | | items[].refundItems[].createdAt | string | | | items[].returnInfo | object | 需要退货时返回:寄回地址与可选快递公司 | | items[].returnInfo.subOrderId | string | | | items[].returnInfo.refunderName | string | | | items[].returnInfo.refunderTel | string | | | items[].returnInfo.refunderAddress | string | | | items[].returnInfo.carriers | object[] | | | items[].returnInfo.carriers[].code | string | | | items[].returnInfo.carriers[].name | string | | | items[].returnInfo.ready | boolean | | **响应示例** ```json { "items": [ { "outTradeNo": "string", "status": "pending_payment", "gateway": "alipay", "tradeNo": "string", "money": "string", "name": "string", "items": [ null ], "receiver": null, "upstreamOrderId": "string", "createdAt": "string", "paidAt": "string", "fulfilledAt": "string", "refundedAt": "string", "refundItems": [ {} ], "returnInfo": { "subOrderId": "string", "refunderName": "string", "refunderTel": "string", "refunderAddress": "string", "carriers": [], "ready": true } } ] } ``` --- ### `GET /v1/lm/pay/orders/{outTradeNo}` — 收款单详情(付款后查它:status = fulfilled 即已下单,带订单号与退款进度) 鉴权:用户态;适用场景:消费者购物 付款后轮询它:`status` 变为 fulfilled 且有 `upstreamOrderId` 即已下单。也用来看退款进度(refundItems)和退货信息(returnInfo)。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | outTradeNo | string | 是 | | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | subOrderId | string | 否 | 退货阶段指定订单行 | **返回字段(平台收款单)** | 字段 | 类型 | 说明 | |---|---|---| | outTradeNo | string | 收款单号 | | status | string | 可选值:`pending_payment` / `paid` / `fulfilling` / `fulfilled` / `refund_requested` / `awaiting_return` / `returning` / `refund_pending` / `manual_review` / `refunded` / `partially_refunded` / `refund_failed` / `closed` | | gateway | string | 可选值:`alipay` / `wxpay` | | tradeNo | string | | | money | string | 金额(元) | | name | string | | | items | object[] | | | receiver | object | | | upstreamOrderId | string | 付款后平台自动下单得到的采购单号 | | createdAt | string | | | paidAt | string | 可能为 null | | fulfilledAt | string | 可能为 null | | refundedAt | string | 可能为 null | | refundItems | object[] | 详情接口返回:按订单行的退款进度 | | refundItems[].subOrderId | string | | | refundItems[].amount | number | | | refundItems[].status | string | | | refundItems[].createdAt | string | | | returnInfo | object | 需要退货时返回:寄回地址与可选快递公司 | | returnInfo.subOrderId | string | | | returnInfo.refunderName | string | | | returnInfo.refunderTel | string | | | returnInfo.refunderAddress | string | | | returnInfo.carriers | object[] | | | returnInfo.carriers[].code | string | | | returnInfo.carriers[].name | string | | | returnInfo.ready | boolean | | **响应示例** ```json { "outTradeNo": "string", "status": "pending_payment", "gateway": "alipay", "tradeNo": "string", "money": "string", "name": "string", "items": [ null ], "receiver": null, "upstreamOrderId": "string", "createdAt": "string", "paidAt": "string", "fulfilledAt": "string", "refundedAt": "string", "refundItems": [ { "subOrderId": "string", "amount": 0, "status": "string", "createdAt": "string" } ], "returnInfo": { "subOrderId": "string", "refunderName": "string", "refunderTel": "string", "refunderAddress": "string", "carriers": [ { "code": "string", "name": "string" } ], "ready": true } } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `POST /v1/lm/pay/refund` — 退款申请(未发货整单退;多件需指定订单行) 鉴权:用户态;适用场景:消费者购物 按订单行退款,一单多行时 `subOrderId` 必填。未发货原路退款;已发货需要退货的,状态会变为 awaiting_return,寄回后回传运单。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | outTradeNo | string | 是 | | | subOrderId | string | 否 | 订单行 id(orderLineId) | | reasonId | string | 否 | 可选原因 id;不传取第一个可选原因 | | reason | string | 否 | | **请求示例**(只含必填字段) ```json { "outTradeNo": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | status | string | 可选值:`refund_requested` / `awaiting_return` / `refund_pending` | | message | string | | **响应示例** ```json { "ok": true, "status": "refund_requested", "message": "string" } ``` **错误** - 400:`NOT_PAID` / `CLOSED` / `FULFILLING` / `SUB_ORDER_REQUIRED` / `SUB_ORDER_INVALID` / `ALREADY_SHIPPED` / `NO_REMAINING` / `SUBMIT_FAILED` 等 - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `GET /v1/lm/refunds` — 售后列表;render=1 取可退金额与可选原因(选中的原因 id 作为 reasonId 传给退款申请) 鉴权:用户态;适用场景:消费者购物 带 `render=1&orderId=&orderLineId=`:返回这一行的可退金额和可选原因,把选中的 `reasonTextId` 作为 `reasonId` 传给 `POST /v1/lm/pay/refund`(原因随订单状态变化,不要写死;不传时平台取第一条)。不带 render 时返回这个用户的上游售后单列表(可用 orderId 筛选)。上游失败时 200 且 `success: false`。 **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | render | string | 否 | 可选值:`1` | | orderId | string | 否 | 子订单号 | | orderLineId | string | 否 | 订单行 id,render 时必填 | **返回字段(列表时返回 items;render 时返回 success / maxRefundFee / reasons)** | 字段 | 类型 | 说明 | |---|---|---| | items | object[] | | | items[].disputeId | string | 售后单号 | | items[].orderId | string | | | items[].orderLineId | string | | | items[].status | integer | 1 退货待处理 / 2 待买家退货 / 3 待商家收货 / 4 退款关闭 / 5 退款成功 / 6 已拒绝 / 17 取消中 | | items[].displayStatus | string | | | items[].bizClaimType | integer | 1 仅退款 / 3 退货退款 | | items[].amount | number | | | items[].reason | string | | | items[].refunderName | string | | | items[].refunderTel | string | | | items[].refunderAddress | string | | | items[].canSubmitReturn | boolean | | | items[].createdAt | string | | | success | boolean | | | message | string | | | maxRefundFee | number | 最多可退(元) | | reasons | object[] | | | reasons[].reasonTextId | string | | | reasons[].reasonTips | string | | | reasons[].proofRequired | boolean | | | reasons[].refundDescRequired | boolean | | **响应示例** ```json { "items": [ { "disputeId": "string", "orderId": "string", "orderLineId": "string", "status": 0, "displayStatus": "string", "bizClaimType": 0, "amount": 0, "reason": "string", "refunderName": "string", "refunderTel": "string", "refunderAddress": "string", "canSubmitReturn": true, "createdAt": "string" } ], "success": true, "message": "string", "maxRefundFee": 0, "reasons": [ { "reasonTextId": "string", "reasonTips": "string", "proofRequired": true, "refundDescRequired": true } ] } ``` **错误** - 400:render 缺少 orderId / orderLineId - 404:资源不存在,或不归属你的 appKey / 当前用户 --- ### `GET/POST /v1/lm/refunds/{disputeId}` — 售后详情 / 撤销售后(action=cancel) 鉴权:用户态;适用场景:消费者购物 #### GET:售后详情 读取时会同步一次上游状态。钱是否已退到用户手里以收款单 status / refundItems 为准。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | disputeId | string | 是 | | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | disputeId | string | 售后单号 | | orderId | string | | | orderLineId | string | | | status | integer | 1 退货待处理 / 2 待买家退货 / 3 待商家收货 / 4 退款关闭 / 5 退款成功 / 6 已拒绝 / 17 取消中 | | displayStatus | string | | | bizClaimType | integer | 1 仅退款 / 3 退货退款 | | amount | number | | | reason | string | | | refunderName | string | | | refunderTel | string | | | refunderAddress | string | | | canSubmitReturn | boolean | | | createdAt | string | | **响应示例** ```json { "disputeId": "string", "orderId": "string", "orderLineId": "string", "status": 0, "displayStatus": "string", "bizClaimType": 0, "amount": 0, "reason": "string", "refunderName": "string", "refunderTel": "string", "refunderAddress": "string", "canSubmitReturn": true, "createdAt": "string" } ``` **错误** - 404:资源不存在,或不归属你的 appKey / 当前用户 #### POST:撤销售后 用户不想退了时撤销;撤销后收款单回到原状态,钱不退。 **路径参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | disputeId | string | 是 | | **查询参数** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | action | string | 否 | 可选值:`cancel`。默认 `"cancel"` | **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | message | string | | **响应示例** ```json { "ok": true, "message": "string" } ``` **错误** - 400:见 message --- ### `POST /v1/lm/pay/refund/return` — 退货退款:回传退货运单号 鉴权:用户态;适用场景:消费者购物 寄回商品后调用。快递公司编码取自收款单详情的 `returnInfo.carriers`。 **请求体(application/json)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | outTradeNo | string | 是 | | | logisticsCompany | string | 是 | returnInfo.carriers[].code | | invoiceNo | string | 是 | 退货运单号 | | subOrderId | string | 否 | | **请求示例**(只含必填字段) ```json { "outTradeNo": "string", "logisticsCompany": "string", "invoiceNo": "string" } ``` **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | ok | boolean | | | status | string | 例:`returning` | | message | string | | **响应示例** ```json { "ok": true, "status": "returning", "message": "string" } ``` **错误** - 400:`NOT_AWAITING_RETURN` / `BAD_CARRIER` / `RETURN_SUBMIT_FAILED` 等 - 404:资源不存在,或不归属你的 appKey / 当前用户 ## 接入与账户 查当前 appKey 的权限与用量。沙箱 key、签名密钥与 MCP Token 在开发者控制台(open.gowu.net/console)里管理。 ### `GET /v1/access-clients/me` — 当前 appKey 的权限、渠道与调用量 鉴权:appKey;适用场景:员工福利购物 / 企业采购 / 消费者购物 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | appKey | string | | | remark | string | 可能为 null | | createdAt | string | 可能为 null | | apiCallCount | integer | | **响应示例** ```json { "appKey": "string", "remark": "string", "createdAt": "string", "apiCallCount": 0 } ``` --- ### `GET /v1/health` — 健康检查 鉴权:免鉴权;适用场景:员工福利购物 / 企业采购 / 消费者购物 **返回字段** | 字段 | 类型 | 说明 | |---|---|---| | status | string | 例:`ok` | | db | string | 例:`ok` | **响应示例** ```json { "status": "ok", "db": "ok" } ``` **错误** - 500:依赖不可用