文档概述
- 接口总数:25个
- API版本:linkedmall/2023-09-30
- RegionId:cn-zhangjiakou(华北3 张家口)
- Endpoint:
linkedmall.cn-zhangjiakou.aliyuncs.com
- HTTP基础Path前缀:
/opensaas-s2b/opensaas-s2b-biz-trade/v2
- 签名类型:ROA签名,SDK内部自动处理
- 金额单位:分(整数,long/int64)
- 区域编码divisionCode:必须使用五级(乡镇街道级别)编码
认证与安全
- 使用RAM子账号AccessKey(AccessKeyId / AccessKeySecret),禁止主账号AK
- 授予LinkedMall对应OpenAPI最小权限
- 业务前置资源:purchaserId(采购方ID)、shopId(店铺ID),由LinkedMall控制台分配
- 签名类型为ROA签名,SDK内部自动处理,业务无需实现签名算法
- 使用通用OpenApiClient(darabonba-openapi/v2)发起ROA调用
公共返回结构体
所有接口返回外层统一格式:
type CommonResponse struct {
RequestId string `json:"RequestId"`
Success bool `json:"Success"`
Code string `json:"Code"`
Message string `json:"Message"`
SubCode string `json:"SubCode"`
SubMessage string `json:"SubMessage"`
Data interface{} `json:"Data"` // 业务数据,不同接口Data内部结构不同
}
公共Code枚举:
SUCCESS:业务调用成功
- 其他:业务失败,看SubCode、SubMessage定位原因
注意:HTTP 200 不代表业务成功,必须判断 Success==true
SDK客户端初始化
package main
import (
"github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/v2"
)
func NewLinkedMallClient(accessKeyId, accessKeySecret string) (*client.Client, error) {
config := &client.Config{
AccessKeyId: tea.String(accessKeyId),
AccessKeySecret: tea.String(accessKeySecret),
RegionId: tea.String("cn-zhangjiakou"),
Endpoint: tea.String("linkedmall.cn-zhangjiakou.aliyuncs.com"),
ReadTimeout: tea.Int(30000),
ConnectTimeout: tea.Int(10000),
}
return client.NewClient(config)
}
调用示例:
cli, err := NewLinkedMallClient("AKxxx", "SKxxx")
resp, err := cli.RoaRequest(
tea.String("POST"),
tea.String("/opensaas-s2b/opensaas-s2b-biz-trade/v2/xxx"),
nil, // query map[string]*string
bodyObj, // post json body
nil, // header
)
接口列表
接口 1:ListPurchaserShops 获取采购方店铺列表
- 路径:
/purchaser-shops
- 方法:GET
- 描述:分页获取采购方店铺列表
请求参数(Query)
| 参数名 |
类型 |
必填 |
说明 |
| PageNum |
int |
否 |
页码,默认1 |
| PageSize |
int |
否 |
每页条数,最大100 |
响应Data结构体
type ListPurchaserShopsRespData struct {
Total int64 `json:"Total"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
ShopList []PurchaserShopItem `json:"ShopList"`
}
type PurchaserShopItem struct {
ShopId string `json:"ShopId"`
PurchaserId string `json:"PurchaserId"`
ShopName string `json:"ShopName"`
ShopStatus string `json:"ShopStatus"`
}
接口 2:GetPurchaserShop 获取采购方店铺详情
- 路径:
/purchaser-shops/{ShopId}
- 方法:GET
- 描述:获取单个采购店铺详情
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| ShopId |
string |
Path |
是 |
店铺ID |
响应Data结构体
type GetPurchaserShopRespData struct {
ShopId string `json:"ShopId"`
PurchaserId string `json:"PurchaserId"`
ShopName string `json:"ShopName"`
ShopStatus string `json:"ShopStatus"`
ContactInfo string `json:"ContactInfo"`
}
接口 3:ListSelectionProducts 查询选品池商品列表
- 路径:
/selection-products
- 方法:GET
- 描述:分页查询选品池商品列表
请求参数(Query)
| 参数名 |
类型 |
必填 |
说明 |
| PageNum |
int |
否 |
页码 |
| PageSize |
int |
否 |
最大100 |
| PurchaserId |
string |
是 |
采购方ID |
响应Data结构体
type ListSelectionProductsRespData struct {
Total int64 `json:"Total"`
PageNum int `json:"PageNum"`
PageSize int `json:"PageSize"`
ProductList []SelectionProductItem `json:"ProductList"`
}
type SelectionProductItem struct {
ProductId string `json:"ProductId"`
Title string `json:"Title"`
MainImage string `json:"MainImage"`
BrandName string `json:"BrandName"`
CategoryId string `json:"CategoryId"`
}
接口 4:GetSelectionProduct 查询选品池商品详情
- 路径:
/selection-products/{ProductId}
- 方法:GET
- 描述:查询单个商品详情,支持传入divisionCode校验区域可售库存
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| ProductId |
string |
Path |
是 |
商品ID |
| PurchaserId |
string |
Query |
是 |
采购方ID |
| DivisionCode |
string |
Query |
否 |
五级乡镇区域编码,传后返回该区域可售状态 |
响应Data结构体
type GetSelectionProductRespData struct {
ProductId string `json:"ProductId"`
Title string `json:"Title"`
MainImage string `json:"MainImage"`
Images []string `json:"Images"`
BrandName string `json:"BrandName"`
CategoryId string `json:"CategoryId"`
Desc string `json:"Desc"`
SkuList []SelectionSkuItem `json:"SkuList"`
CanSale bool `json:"CanSale"` // 传入divisionCode才有效,该区域是否可售
StockQuantity int64 `json:"StockQuantity"`
}
type SelectionSkuItem struct {
SkuId string `json:"SkuId"`
SkuSpec string `json:"SkuSpec"`
SalePrice int64 `json:"SalePrice"` // 单位分
MarketPrice int64 `json:"MarketPrice"`
StockQuantity int64 `json:"StockQuantity"`
}
接口 5:GetSelectionProductSaleInfo 查询选品池商品销售信息
- 路径:
/selection-products/{ProductId}/sale-info
- 方法:GET
- 描述:查询商品可售、价格库存快照
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| ProductId |
string |
Path |
是 |
商品ID |
| PurchaserId |
string |
Query |
是 |
采购方ID |
| DivisionCode |
string |
Query |
否 |
五级乡镇区域编码 |
接口 6:ListSelectionProductSaleInfos 批量查询商品销售信息
- 路径:
/selection-products:batch-sale-info
- 方法:POST
- 描述:批量查询商品销售信息
请求Body
{
"PurchaserId": "xxx",
"ProductIdList": ["p1","p2"],
"DivisionCode": "五级编码"
}
接口 7:ListSelectionSkuSaleInfos 批量SKU销售信息
- 路径:
/selection-skus:batch-sale-info
- 方法:POST
- 描述:批量查询SKU销售信息
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| SkuIdList |
[]string |
是 |
SKU ID列表 |
| DivisionCode |
string |
否 |
五级乡镇区域编码 |
接口 8:ListCategories 查询类目列表
- 路径:
/categories
- 方法:GET
- 描述:查询类目列表
请求参数(Query)
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| ParentCategoryId |
string |
否 |
父类目ID(不传查一级类目) |
接口 9:SearchProducts 搜索选品池商品
- 路径:
/selection-products:search
- 方法:POST
- 描述:搜索选品池商品
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| Keyword |
string |
否 |
关键词 |
| CategoryId |
string |
否 |
类目ID |
| PageNum |
int |
否 |
页码 |
| PageSize |
int |
否 |
每页条数 |
| PurchaserId |
string |
是 |
采购方ID |
接口 10:SelectionGroupAddProduct 选品池商品入库
- 路径:
/selection-group/products:add
- 方法:POST
- 描述:选品池商品入库
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| ShopId |
string |
是 |
店铺ID |
| ProductIdList |
[]string |
是 |
商品ID列表 |
接口 11:SelectionGroupRemoveProduct 选品池商品出库
- 路径:
/selection-group/products:remove
- 方法:POST
- 描述:选品池商品出库
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| ShopId |
string |
是 |
店铺ID |
| ProductIdList |
[]string |
是 |
商品ID列表 |
接口 12:RenderPurchaseOrder 采购单渲染(下单预校验)
- 路径:
/purchase-orders:render
- 方法:POST
- 描述:下单前必须调用,获取实时价格、校验商品是否可售
请求Body
type RenderPurchaseOrderReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
DivisionCode string `json:"DivisionCode"` // 五级乡镇编码
ItemList []RenderOrderItem `json:"ItemList"`
ReceiverInfo ReceiverInfo `json:"ReceiverInfo"`
}
type RenderOrderItem struct {
SkuId string `json:"SkuId"`
Quantity int64 `json:"Quantity"`
}
type ReceiverInfo struct {
ReceiverName string `json:"ReceiverName"`
ReceiverPhone string `json:"ReceiverPhone"`
ProvinceCode string `json:"ProvinceCode"`
CityCode string `json:"CityCode"`
DistrictCode string `json:"DistrictCode"`
TownCode string `json:"TownCode"`
DetailAddress string `json:"DetailAddress"`
}
响应Data
渲染后的价格、商品校验结果、不可售原因、预估运费。
接口 13:SplitPurchaseOrder 采购单渲染并拆单
- 路径:
/purchase-orders:split-render
- 方法:POST
- 描述:采购单渲染并拆单,返回拆成多份子单结构
请求Body
结构和RenderPurchaseOrderReq完全一致
响应Data
返回拆成多份子单结构,用于前端展示,拆单结果用于创建采购单入参。
接口 14:CreatePurchaseOrder 创建采购单【异步】
- 路径:
/purchase-orders
- 方法:POST
- 描述:⚠️重要:接口只返回采购单号,不代表下单成功,必须等待回调通知,再查询订单接口
请求Body
type CreatePurchaseOrderReq struct {
PurchaserId string `json:"PurchaserId"`
ShopId string `json:"ShopId"`
OuterPurchaseOrderId string `json:"OuterPurchaseOrderId"` // 外部业务唯一单号,幂等
DivisionCode string `json:"DivisionCode"`
ReceiverInfo ReceiverInfo `json:"ReceiverInfo"`
SubOrderList []CreateSubOrderItem `json:"SubOrderList"` // SplitPurchaseOrder返回的子单
}
type CreateSubOrderItem struct {
SkuId string `json:"SkuId"`
Quantity int64 `json:"Quantity"`
}
响应Data结构体
type CreatePurchaseOrderRespData struct {
PurchaseOrderId string `json:"PurchaseOrderId"` // 阿里云采购单号
}
接口 15:GetPurchaseOrderStatus 获取采购单状态
- 路径:
/purchase-orders/{PurchaseOrderId}/status
- 方法:GET
- 描述:获取采购单状态
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| PurchaseOrderId |
string |
Path |
是 |
采购单ID |
| PurchaserId |
string |
Query |
是 |
采购方ID |
响应Data
采购单状态枚举:INIT、PROCESS、SUCCESS、FAIL、CLOSED
接口 16:GetOrder 获取订单详情
- 路径:
/orders/{OrderId}
- 方法:GET
- 描述:获取订单详情
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| OrderId |
string |
Path |
是 |
订单ID |
| PurchaserId |
string |
Query |
是 |
采购方ID |
响应Data
订单主信息、商品明细、实付金额、状态、收货信息
接口 17:QueryOrders 查询订单列表
- 路径:
/orders
- 方法:GET
- 描述:查询订单列表
请求参数(Query)
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| PurchaseOrderId |
string |
否 |
采购单ID |
| PageNum |
int |
否 |
页码 |
| PageSize |
int |
否 |
每页条数 |
| StartTime |
string |
否 |
开始时间 |
| EndTime |
string |
否 |
结束时间 |
接口 18:ListLogisticsOrders 查询订单物流信息
- 路径:
/orders/{OrderId}/logistics
- 方法:GET
- 描述:查询订单物流信息
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| OrderId |
string |
Path |
是 |
订单ID |
| PurchaserId |
string |
Query |
是 |
采购方ID |
响应Data
运单号、物流公司、物流轨迹数组
接口 19:ConfirmDisburse 确认收货
- 路径:
/orders/{OrderId}:confirm-disburse
- 方法:POST
- 描述:确认收货
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| OrderId |
string |
Path |
是 |
订单ID |
请求Body
{"PurchaserId":"xxx"}
接口 20:RenderRefundOrder 售后渲染预校验
- 路径:
/refund-orders:render
- 方法:POST
- 描述:售后渲染预校验
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| OrderId |
string |
是 |
订单ID |
| OrderItemId |
string |
是 |
订单商品明细ID |
| RefundQuantity |
int64 |
是 |
退款数量 |
| RefundType |
string |
是 |
退款类型(仅退款/退货退款) |
接口 21:CreateRefundOrder 创建售后单
- 路径:
/refund-orders
- 方法:POST
- 描述:创建售后单
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| OrderId |
string |
是 |
订单ID |
| OrderItemId |
string |
是 |
订单商品明细ID |
| RefundQuantity |
int64 |
是 |
退款数量 |
| RefundAmount |
int64 |
是 |
退款金额(单位分) |
| RefundType |
string |
是 |
退款类型 |
| RefundReason |
string |
是 |
退款原因 |
| OuterRefundNo |
string |
是 |
外部售后单号 |
接口 22:CancelRefundOrder 取消售后单
- 路径:
/refund-orders/{RefundOrderId}:cancel
- 方法:POST
- 描述:取消售后单
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| RefundOrderId |
string |
Path |
是 |
售后单ID |
请求Body
{"PurchaserId":"xxx"}
接口 23:GetRefundOrder 获取售后单详情
- 路径:
/refund-orders/{RefundOrderId}
- 方法:GET
- 描述:获取售后单详情
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| RefundOrderId |
string |
Path |
是 |
售后单ID |
| PurchaserId |
string |
Query |
是 |
采购方ID |
接口 24:CreateGoodsShippingNotice 回填退货物流运单
- 路径:
/refund-orders/{RefundOrderId}:fill-logistics
- 方法:POST
- 描述:回填退货物流运单
请求参数
| 参数名 |
类型 |
位置 |
必填 |
说明 |
| RefundOrderId |
string |
Path |
是 |
售后单ID |
请求Body参数
| 参数名 |
类型 |
必填 |
说明 |
| PurchaserId |
string |
是 |
采购方ID |
| LogisticsCompany |
string |
是 |
物流公司 |
| TrackingNumber |
string |
是 |
运单号 |
接口 25:QueryChildDivisionCode 查询子区域编码
- 路径:
/divisions:children
- 方法:GET
- 描述:查询子区域编码,不传返回省级;传入省返回市,传入市返回区,传入区返回乡镇(五级)
请求参数(Query)
| 参数名 |
类型 |
必填 |
说明 |
| ParentDivisionCode |
string |
否 |
父区域编码 |
响应Data
DivisionCode列表、名称、层级;下单、商品可售校验必须拿到乡镇级DivisionCode
错误码
| 错误码 |
说明 |
处理建议 |
| ShopTypeInvalid |
SKU属于经销集采店铺,不可下单 |
过滤SKU |
| SkuPriceUnique |
SKU价格非最新 |
重新调用RenderPurchaseOrder获取最新价格再下单 |
| PurchaseOrderNotFound |
采购单号不存在 |
核对入参PurchaseOrderId |
| RefundNumberMustLessThanOrder |
退款数量大于订单商品数量 |
修正退款数量 |
| RefundAmountMustLessThanOrder |
退款金额大于实付金额 |
修正退款金额 |
| HasNoPrivilege |
RAM无接口权限 |
检查RAM授权策略 |
| OrderNotFound |
订单ID不存在 |
核对OrderId |
| ShopNotFind |
店铺不存在 |
核对ShopId/PurchaserId |
| SavePurchaseOrderError |
保存采购单服务端异常 |
短间隔重试 |
| OuterPurchaseOrderIdExist |
外部业务单号重复 |
更换OuterPurchaseOrderId,做好幂等 |
回调通知
消息回调(异步通知)规范
CreatePurchaseOrder创建采购单后,阿里云主动POST回调业务配置的回调地址。
- 请求方式:POST,Content-Type: application/json
- 业务侧需要返回
{"success":true} 告知阿里云消费成功;否则阿里云会重试推送。
- 回调Body公共字段:
{
"EventCode": "PURCHASE_ORDER_CHANGE",
"PurchaseOrderId": "xxx",
"OrderIdList": ["附属真实订单ID数组"],
"Status": "SUCCESS/FAIL",
"RequestId": "xxx"
}
EventCode枚举:
- PURCHASE_ORDER_CHANGE:采购单状态变更
- ORDER_STATUS_CHANGE:订单状态变更
- REFUND_ORDER_CHANGE:售后单变更
业务处理逻辑:收到回调后,调用对应查询接口拉取最新业务数据做本地状态同步。
完整业务调用流程
- 调用
QueryChildDivisionCode 获取五级乡镇divisionCode(收货地址对应的区域编码)
- 调用
ListSelectionProducts / SearchProducts 获取选品池商品SkuId
- 调用
RenderPurchaseOrder 预渲染校验商品可售、价格
- 调用
SplitPurchaseOrder 获取拆单结果
- 调用
CreatePurchaseOrder,传入外部唯一业务单号OuterPurchaseOrderId,拿到PurchaseOrderId
- 等待阿里云消息回调通知
- 回调收到事件,调用
GetPurchaseOrderStatus看采购单状态;拿到附属OrderId调用GetOrder同步订单入库本地库
- 后续:查物流、确认收货;产生售后调用售后接口
❗禁止:CreatePurchaseOrder同步返回成功直接标记本地订单成功。
开发注意事项
- 金额全部为分(int64),Go使用int64,不要float64;JSON序列化不要丢失long精度
- DivisionCode必须五级乡镇,否则商品可售校验错误
- OuterPurchaseOrderId外部采购单号全局唯一,用于幂等防重复下单
- CreatePurchaseOrder异步,依赖回调;不能轮询频率过高
- RAM子账号最小权限,AK禁止硬编码代码,环境变量配置
- 所有接口必须判断外层返回
Success==true,HTTP 200不等于业务成功
- 分页接口PageSize上限100,不要传超大值
- 回调接口做好幂等,同一个事件可能多次推送