goods_list + goods_detail 同步商品信息order_buy 向主站下单out_trade_no 必须唯一且不可重复,建议使用你系统的订单号out_trade_no 重复调用不会多扣费order_query(用 out_trade_no)查询是否已下单成功order_buy 返回 status=1 时,表示需要人工发货order_query 查询未完成订单status ≥ 2 且 content 非空时,表示发货完成,同步发货内容到本地order_query,实现用户触发式轮询guest_price 是你的采购成本价(已根据你的会员等级折扣后),建议在此基础上加价后作为你本地的销售价market_price(原价)用于本地的划线价展示sku 值由规格值 ID 组合而成,格式为 id1-id2spec 数据以更新本地规格名称和 ID 映射sku 值传给 order_buy以下是一个封装好的 PHP 对接类,你可以直接复制使用:
<?php
/**
* DCShop 同系统对接客户端
* 使用方法:
* $client = new DockingClient('https://主站域名', 'YOUR_API_KEY');
* $goods = $client->goodsList(1, 1, 20); // 获取分类1的商品
* $detail = $client->goodsDetail(12); // 获取商品12的详情
* $order = $client->orderBuy(12, 1, '0', 'MY001'); // 下单
* $query = $client->orderQuery('订单号'); // 查询订单
* $info = $client->userInfo(); // 查询余额
*/
class DockingClient {
private $baseUrl;
private $apiKey;
private $timeout;
public function __construct($siteUrl, $apiKey, $timeout = 30) {
$this->baseUrl = rtrim($siteUrl, '/') . '/user/api.php';
$this->apiKey = $apiKey;
$this->timeout = $timeout;
}
/** 获取商品分类 */
public function goodsCategory() {
return $this->get('goods_category');
}
/** 获取商品列表 */
public function goodsList($cid = 0, $page = 1, $limit = 20) {
$params = ['page' => $page, 'limit' => $limit];
if ($cid > 0) $params['cid'] = $cid;
return $this->get('goods_list', $params);
}
/** 获取商品详情 */
public function goodsDetail($goodsId) {
return $this->get('goods_detail', ['id' => $goodsId]);
}
/** 下单购买 */
public function orderBuy($goodsId, $quantity, $sku, $outTradeNo) {
return $this->post('order_buy', [
'goods_id' => $goodsId,
'quantity' => $quantity,
'sku' => $sku ?: '0',
'out_trade_no' => $outTradeNo,
]);
}
/** 查询订单(用主站订单号) */
public function orderQuery($orderId) {
return $this->get('order_query', ['order_id' => $orderId]);
}
/** 查询订单(用商户单号) */
public function orderQueryByTradeNo($outTradeNo) {
return $this->get('order_query', ['out_trade_no' => $outTradeNo]);
}
/** 查询账户信息 */
public function userInfo() {
return $this->get('user_info');
}
// ─── 内部方法 ───
private function get($action, $params = []) {
$params['action'] = $action;
$params['api_key'] = $this->apiKey;
$url = $this->baseUrl . '?' . http_build_query($params);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
]);
return $this->execute($ch);
}
private function post($action, $data = []) {
$url = $this->baseUrl . '?action=' . $action;
$data['api_key'] = $this->apiKey;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
]);
return $this->execute($ch);
}
private function execute($ch) {
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return ['code' => -1, 'msg' => '网络错误: ' . $error, 'data' => ''];
}
$result = json_decode($response, true);
if (!is_array($result)) {
return ['code' => -1, 'msg' => '响应解析失败 (HTTP ' . $httpCode . ')', 'data' => ''];
}
return $result;
}
}
<?php
require_once 'DockingClient.php';
$client = new DockingClient('https://货源站域名', 'YOUR_API_KEY');
// 1. 检查余额
$info = $client->userInfo();
if ($info['code'] !== 0) {
die('鉴权失败: ' . $info['msg']);
}
echo "当前余额: ¥" . $info['data']['money'] . "\n";
echo "会员等级: " . $info['data']['level_name'] . "\n";
// 2. 查看商品详情
$detail = $client->goodsDetail(12);
if ($detail['code'] !== 0) {
die('获取商品失败: ' . $detail['msg']);
}
$goods = $detail['data'];
echo "商品: " . $goods['title'] . "\n";
echo "采购价: ¥" . $goods['skus'][0]['guest_price'] . "\n";
echo "库存: " . $goods['stock'] . "\n";
// 3. 下单购买
$myOrderNo = 'DOCK' . date('YmdHis') . mt_rand(1000, 9999);
$order = $client->orderBuy($goods['id'], 1, '0', $myOrderNo);
if ($order['code'] !== 0) {
die('下单失败: ' . $order['msg']);
}
$remoteOrderId = $order['data']['order_id'];
$status = (int)$order['data']['status'];
echo "主站订单号: " . $remoteOrderId . "\n";
// 4. 判断是否需要轮询
if ($status >= 2) {
// 自动发货,直接拿到卡密
echo "发货内容:\n" . $order['data']['content'] . "\n";
} else {
// 人工发货,需要定时轮询
echo "订单等待人工发货,开始轮询...\n";
for ($i = 0; $i < 60; $i++) { // 最多轮询 60 次,共 5 分钟
sleep(5);
$query = $client->orderQuery($remoteOrderId);
if ($query['code'] === 0 && (int)$query['data']['status'] >= 2) {
echo "发货完成!\n";
echo "发货内容:\n" . $query['data']['content'] . "\n";
break;
}
echo "第 " . ($i + 1) . " 次轮询,状态: 待发货\n";
}
}
主站的商品有不同类型,对接时需了解各类型的发货特性:
| 类型标识 | 名称 | 发货方式 | 对接说明 |
|---|---|---|---|
duli |
独立卡密 | 自动发货 | order_buy 返回 status=2,content 中直接包含卡密 |
guding |
固定卡密 | 自动发货 | 与独立卡密类似,自动返回发货内容 |
xuni |
虚拟服务 | 人工发货 |
order_buy 返回 status=1,需要等待主站管理员人工处理后通过 order_query 轮询获取发货内容。
⚠️ 注意: content 可能有模板占位文字,必须以 status ≥ 2 为准!
|
status 字段判断发货状态。自动发货商品会立即返回 status=2,人工发货商品返回 status=1 后需要轮询。在主站注册账号后,联系主站管理员开通 API 对接权限。管理员会为你的账号生成 api_key,并在后台设置你可对接的商品范围。
建议合理控制调用频率。商品同步建议 5~10 分钟一次;订单轮询建议 3~5 分钟一次。过于频繁的调用可能被主站限流或拉黑。
不用担心!直接使用同一个 out_trade_no 重新调用 order_buy,系统会自动识别并返回之前的订单结果,不会重复扣费。或者调用 order_query 用 out_trade_no 查询。
可能的原因:
is_on_shelf = 0)allow_dock = 0)不需要提前判断。统一走 order_buy 下单,根据返回的 status 字段判断即可。status=2 就是已完成,status=1 就需要轮询 order_query。
完全可以!本 API 是标准的 HTTP + JSON 接口,任何语言和系统都可以对接。你只需要:
先调用 goods_detail 获取 spec 和 skus 数据。spec 包含规格维度和选项,skus 包含每种组合的库存与价格。用户选择后,将对应规格值的 id 用 - 拼接传给 order_buy 的 sku 参数。