维修端与供应端已有 ERP / 进销存系统(金蝶、用友、管家婆等),通过本接口与系统自动同步订单、库存与对账数据
AppSecret 仅在开通 / 重置时完整显示一次,请妥善保存;泄露可随时在端内一键重置。应用可停用,停用后全部调用立即被拦截。
所有接口通过 HTTP 请求头鉴权,四个头缺一不可:
| 请求头 | 说明 |
|---|---|
X-App-Key | 开通应用时分配的 AppKey(erp_ 开头) |
X-Timestamp | 当前毫秒时间戳,与服务器误差须在 ±5 分钟内 |
X-Nonce | 8~64 位随机串,10 分钟内不可重复(防重放) |
X-Sign | 签名,见下方算法 |
bodyHash = SHA256_HEX(原始请求体字符串) // GET 请求为空字符串 ""
signStr = AppKey + "\n" + Timestamp + "\n" + Nonce + "\n" + bodyHash
X-Sign = HMAC_SHA256_HEX(AppSecret, signStr)
限流:每应用每分钟 120 次。签名错误、时间戳过期、Nonce 重放均返回 code:-1 与中文错误说明。
const crypto = require('crypto');
const APP_KEY = 'erp_xxxxxxxx', APP_SECRET = 'sk_xxxx';
const BASE = 'http://162.14.118.157:3000';
async function callApi(method, path, body) {
const raw = body ? JSON.stringify(body) : '';
const ts = String(Date.now());
const nonce = crypto.randomBytes(12).toString('hex');
const bodyHash = crypto.createHash('sha256').update(raw).digest('hex');
const sign = crypto.createHmac('sha256', APP_SECRET)
.update([APP_KEY, ts, nonce, bodyHash].join('\n')).digest('hex');
const res = await fetch(BASE + '/api/open/erp/v1' + path, {
method, headers: { 'Content-Type': 'application/json',
'X-App-Key': APP_KEY, 'X-Timestamp': ts, 'X-Nonce': nonce, 'X-Sign': sign },
body: raw || undefined });
const j = await res.json();
if (j.code !== 0) throw new Error(j.msg);
return j.data;
}
// 示例:厂家 ERP 拉取待接单采购单
const orders = await callApi('GET', '/orders?status=' + encodeURIComponent('已接单'));
console.log(orders);
import hashlib, hmac, json, time, requests, secrets APP_KEY, APP_SECRET = 'erp_xxxxxxxx', 'sk_xxxx' BASE = 'http://162.14.118.157:3000' def call_api(method, path, body=None): raw = json.dumps(body, ensure_ascii=False) if body else '' ts = str(int(time.time() * 1000)) nonce = secrets.token_hex(12) body_hash = hashlib.sha256(raw.encode()).hexdigest() sign = hmac.new(APP_SECRET.encode(), f'{APP_KEY}\n{ts}\n{nonce}\n{body_hash}'.encode(), hashlib.sha256).hexdigest() r = requests.request(method, BASE + '/api/open/erp/v1' + path, data=raw or None, headers={'Content-Type': 'application/json', 'X-App-Key': APP_KEY, 'X-Timestamp': ts, 'X-Nonce': nonce, 'X-Sign': sign}) j = r.json() assert j['code'] == 0, j['msg'] return j['data']
| 方法 | 路径(前缀 /api/open/erp/v1) | 说明 | 适用端 |
|---|---|---|---|
| GET | /ping | 连通性测试,返回主体信息与可用接口清单 | 两端 |
| GET | /orders?status=&since= | 采购单列表。status 按状态过滤(待接单/已接单/已发货/已完成);since 按创建时间增量拉取(如 2026-10-01) | 两端 |
| GET | /orders/{id} | 采购单详情(含物流轨迹节点) | 两端 |
| POST | /orders/{id}/ship | 回传发货:{express, expressNo, freight, auto};auto:true 走系统自动叫单 | 厂家 |
| GET | /inventory | 库存查询:厂家返回商品库存(含仓位号);门店返回库存台账 | 两端 |
| POST | /inventory/sync | 库存同步(绝对值覆盖):{items:[{partId 或 oe, qty, bin?}]},单次 ≤500 条,返回 updated 与 unmatched 明细 | 两端 |
| GET | /settlements?month=YYYY-MM | 月度对账:厂家=已完成采购单合计;门店=清分流水合计与明细 | 两端 |
数据隔离:每个应用仅能访问本主体(本店/本厂)的数据,越权访问返回「采购单不存在 / 未匹配到商品」。
在端内配置回调地址后,系统将以下事件实时 POST 推送到你的 ERP:
| 事件 | 触发时机 | 接收方 |
|---|---|---|
order.created | 门店创建采购单(含厂家一键补货代下单) | 厂家 ERP |
order.shipped | 厂家发货(端内操作或 ERP 回传) | 门店 ERP |
order.received | 门店签收采购单,自动入库存台账 | 厂家 ERP |
推送体:{ "event": "order.shipped", "t": "...", "data": {采购单对象} }
推送头与接口调用使用同一套签名规则(X-App-Key / X-Timestamp / X-Nonce / X-Sign + X-Event),你的 ERP 应按同一算法验签,防止伪造推送。验签后对系统返回 2xx 即视为送达;失败记录可在端内「开放接口 → Webhook 推送日志」查看。
| 返回 | 含义与处理 |
|---|---|
| 缺少鉴权头 | 四个签名头缺一,检查请求头大小写与拼写 |
| 时间戳无效或已过期 | 服务器允许 ±5 分钟误差,请校准 ERP 服务器时钟(NTP) |
| X-Nonce 已使用 | 同一随机串 10 分钟内重复,请每次请求重新生成 |
| 签名校验失败 | 核对拼接顺序(AppKey→Timestamp→Nonce→bodyHash)、换行为 \n、bodyHash 用原始请求体、HMAC 输出十六进制小写 |
| 触发限流 | 每应用每分钟 120 次,批量同步请合并到 inventory/sync 单次 ≤500 条 |
| 应用已停用 | 主账号在端内「设置 → 开放接口」重新启用 |
全部调用与推送均在端内留痕(接口、结果、耗时、失败原因),主账号可随时审计。
系统另保留总台签发的简易 Key 接口(/api/open/v1/*:配件目录、采购单查询、代发起售后),面向保险公司、充电站、公共事业缴费等外部资源接入;本文档的 ERP 体系(/api/open/erp/v1/*)面向门店与厂家的内部系统对接,密钥由本端主账号自助管理。两者互不影响。
门户:道驰云修 · 汽车维修数字系统 · 技术支持请联系系统总台