这个功能用来做什么
把商城中已配置的卡密商品作为货源,供阿奇索(Agiso)店铺采购。店主先绑定自己的商城会员账户并同意余额采购;阿奇索发起采购后,商城创建订单、扣款、分配真实卡密,再返回结果。
扣款账户是店主绑定的商城会员账户。 请先给该商城账户充值。外部店铺买家付款、阿奇索侧订单已收款,都不等于商城采购已支付;本接口不会直接扣外部平台钱包,也不会自动拿外部销售收入抵扣。
当前接入只供卡密商品,不提供直充、阿奇索独立查单接口或自动退款接口。普通商城购买仍从商城首页下单;本说明只适用于渠道供货。
开始前准备什么
| 谁准备 | 需要准备的内容 |
|---|---|
| 商城管理员 | 可访问的商城 HTTPS 域名、有效运行授权、正确的履约加密配置 |
| 商城管理员 | 已发布的卡密商品、实际 SKU 和可用卡池;商品处于采购账户与分站的可售范围 |
| 平台对接人员 | 向 Agiso 申请供应商资格,取得 SupplierId、ClientId、ClientSecret,并确认完整授权回调地址 |
| 店主 | 正常商城会员、渠道供货权限、足够商城余额,确认采购所属主站或分站 |
渠道供货权限与客户开放 API 权限独立。不需要先生成开放 API 的 key/secret。 管理员开放权限只是允许接入,仍需启用网关、配置商品映射,由店主亲自确认余额采购授权。
在哪里配置
商城管理员进入「用户管理 → 电商渠道供货」。页面有「客户权限」「供货网关」「商户绑定」「采购订单」四个页签。
- 在「客户权限」找到店主会员,设为「手动允许」并保存;也可设置默认开放,未单独设置的客户跟随默认。客户的手动允许/禁止优先于默认规则,会员停用仍不能采购。
- 进入「供货网关」,在「阿奇索 Agiso」一行点击「配置」。两家渠道独立配置,初始网关关闭。
- 填写平台提供的 SupplierId、ClientId、ClientSecret,以及平台确认的完整 HTTPS 授权回调地址。回调每行一个,精确匹配,最多 10 个;不能写通配符、域名前缀,地址不能带查询串或片段。
- 设置授权有效天数和单笔采购上限。有效期 1–90 天,默认 30 天;上限为整数分,配置范围 1–100,000,000 分。例如 2000 分是 20.00 元。
- 添加供货商品映射,填写「供货编码」「商城商品 ID」「商城 SKU ID」,勾选映射启用。最多 200 个映射,供货编码不能重复。
- 先核对配置与商品;准备好测试账户和真实余额后,在受控联调时启用网关,再进行下文会员授权。网关关闭时无法完成授权或供货调用。
供货编码是给阿奇索使用的商品标识,可采用 UUID;它通过映射对应商城 SKU,不要求与商城 SKU ID 相同。编码使用 1–80 位英文字母、数字、_、-。商品名称不能代替 ID。卡密映射商品不能要求额外的下单资料字段,且需有扣除占用后的真实可用卡密。
ClientSecret 留空保存会保留原值,不代表清空。后台不回显密钥明文;敏感配置、卡密按作用域加密保存,授权 code 与 token 只存 SHA-256 摘要。
看不到页面或按钮时
| 操作 | 所需后台权限 |
|---|---|
| 读取配置、进入供货页面 | site.settings.read |
| 保存配置、修改默认开放规则 | site.settings.write |
| 查看客户权限和商户绑定 | members.read |
| 修改客户单独权限 | members.write |
| 查看采购订单、查询原订单 | members.read、orders.read、payments.read、fulfillment.read |
| 撤销他人绑定 | members.read、members.write |
页面权限与操作权限分别检查。finance.read 是供应商结算相关权限,不能代替 payments.read。
店主怎样绑定和撤销
- 在采购所属主站或分站登录自己的商城会员。
- 进入会员「开放 API / 接口管理 → 电商渠道授权 → 阿奇索供货授权」,或打开:
https://商城域名/developer/channel-supplier.html?provider=agiso- 点击「打开阿奇索授权入口」,从平台发起绑定。也可使用平台入口:
https://alds.agiso.com/supplier/authorize?supplierId=实际SupplierId- 平台回到商城授权页后,核对会员、当前站点和单笔上限。未登录时先点击「登录商城账户」,登录后回到授权页重新读取账户。
- 勾选允许使用本商城余额采购的同意项,再点击「确认授权」。仅登录或访问页面不会自动授权。
授权成功后,商城将一次性 code 和原 state 带回允许列表中的回调地址,由平台换取 token。code 有效期 3 分钟且仅能交换一次;token 随该次授权到期,授权期限从确认授权时开始。重新授权会替换旧凭据。
会员可在同页点击「撤销授权」;管理员可在「商户绑定」页签撤销。撤销立即阻断后续凭据访问,但不会撤回已完成的扣款或交付。确认与撤销必须从本站页面提交,服务端校验同站 Origin,拒绝跨站浏览器提交。
第一次怎样确认成功
- 确认「商户绑定」中会员和站点正确、凭据有效;平台能列出映射的卡密商品。
- 核对单价和库存。Agiso 列表的
Price是元字符串,如"20.00";后台单笔限额的填写单位仍是分。 - 仅发起一笔已经确认的测试采购。成功需同时满足
IsError=false、Code=10000,并有数量正确、内容非空的CardPwdList。 - 在后台「采购订单」确认交付成功;在该会员「我的订单」「资金中心」核对商城订单、实际卡密和一次余额扣款。
- 网络超时保留原采购号,用原参数和新的时间戳、签名查询原结果,不要换号再买。
测试会扣真实商城余额并消耗卡密,已交付卡密不能通过当前退款确认流程直接退款。余额不足时先补足资金,具体是否能重试见下文,不能把 HTTP 200 当作采购成功。
完整接口清单
登记接口时使用采购所属商城域名;ApiUrl 不附加最后的方法名:
AuthUrl https://商城域名/supplier/agiso/authorize
GetTokenUrl https://商城域名/supplier/agiso/token
ApiUrl https://商城域名/supplier/agiso/api| 方法 | 完整路径 | 用途 |
|---|---|---|
| GET | /supplier/agiso/authorize | 登录与显式授权入口 |
| POST | /supplier/agiso/token | 一次性 code 换 token |
| POST | /supplier/agiso/api/categoryList | 可售卡密、单价、库存 |
| POST | /supplier/agiso/api/purchase | 余额采购;同号重试读取原结果 |
本商城未提供该协议下独立的单品详情、查单、余额、退款或异步供货通知方法。单品价格和库存从 categoryList 获取;采购结果通过同参数重试 purchase 或后台「查询原订单」核对。
授权与 token
以下域名、凭据、订单号和响应内容均为结构示例。redirect_uri 必须替换为实际登记、确认过的 HTTPS 回调,不应直接照用示例。
GET /supplier/agiso/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Falds.agiso.com%2FLoginCardPwdSupplier&state=opaque-state| 参数 | 规则 |
|---|---|
response_type | 必须为 code |
client_id | 与商城已配置的 ClientId 一致 |
redirect_uri | 与完整允许地址精确匹配 |
state | 回传用的状态值,最多 1024 字节;平台应校验回传值 |
重复查询字段会被拒绝。该入口校验后跳转商城确认页,不会仅凭访问 URL 直接扣款或授权。
换 token 只接受以下两个表单字段,不额外要求 client_secret 或 sign:
POST /supplier/agiso/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=ONE_TIME_CODE{"IsError":false,"Code":10000,"Msg":"","Token":"ACCESS_TOKEN","ExpireDate":"2030-01-01 12:00:00"}ExpireDate 是实际授权到期时间,按 UTC 格式化,字符串没有时区后缀。过期、已消费的 code 返回 IsError=true。换码每个站点每分钟最多 60 次,包括无效 code 尝试;商户 API 每授权每分钟最多 120 次。请求正文上限 64 KiB(65,536 字节)。
表单签名
categoryList、purchase 使用供应商 ClientSecret,所有业务字段放在 application/x-www-form-urlencoded 正文内。
sign = hexLower(MD5(UTF8(ClientSecret + concat(sortedKey + originalValue) + ClientSecret)))
timestamp = 当前 Unix 秒,允许前后 300 秒计算时排除 sign,参数名按 ASCII 升序,依次连接 key 与表单解码后的原始 value,不加 =、& 或其他分隔符。不要 trim 值,不要对 URL 编码后的 %xx 文本求签名。最后在头尾各拼一次 ClientSecret,再求 UTF-8 小写 MD5。
时间戳用正常十进制秒,不用毫秒、前导零或 + 前缀。阿奇索自动发货 API 的 Bearer/AppSecret 协议与这里不同;商城开放 API 的 HMAC 也不能混用。
可售卡密列表
POST /supplier/agiso/api/categoryList
Content-Type: application/x-www-form-urlencoded
access_token=ACCESS_TOKEN&key_word=&page_no=1&page_size=20×tamp=1893456000&sign=00000000000000000000000000000000固定时间戳和零串签名只展示字段,实际请求必须实时生成。
| 字段 | 规则 |
|---|---|
access_token | 换码得到的 Token |
key_word | 名称关键词或完整供货编码;无关键词也必须发送空字段 |
page_no | 1–10000 |
page_size | 1–100 |
timestamp | 当前秒级时间戳 |
sign | 按本次全部表单字段计算,签名时排除本字段 |
缺少、多余或重复表单字段均拒绝。翻页读取时使用 TotalRecord 判断数量,不要只取第一页。
{"IsError":false,"Code":10000,"Msg":"","TotalRecord":1,"CardCategoryList":[{"Id":"sku-example","Name":"月卡 / 标准版","Price":"20.00","Quantity":3}]}Id 是配置的供货编码;Price 是元字符串;Quantity 是扣除占用后的真实可用卡密数。列表不锁库存,采购仍重新校验实际价格、库存、实名、购买策略与销售时段。
余额采购
POST /supplier/agiso/api/purchase
Content-Type: application/x-www-form-urlencoded
access_token=ACCESS_TOKEN&tid=STORE_ORDER_001&oid=LINE_001&cpc_id=sku-example&num=1&type=Pay×tamp=1893456000&sign=00000000000000000000000000000000| 字段 | 规则 |
|---|---|
access_token、timestamp、sign | 与列表认证规则相同 |
tid | 外部主订单号,1–80 位英文字母、数字、_、- |
oid | 外部订单明细号,字符规则同 tid |
cpc_id | 已启用的供货编码,字符串,字符规则同 tid |
num | 整数 1–999,并满足商品购买规则 |
type | 仅 Pay、Confirm、Rated、Create,大小写按示例 |
这些字段全部必传,不接受额外参数。Agiso 采购没有每次请求的 max_amount 字段,整单限额取网关与该会员授权单笔上限的较小值。采购价格使用服务端实时报价。
成功示例:
{"IsError":false,"Code":10000,"Msg":"","OrderSn":"mall-supplier-order-id","Amount":20.00,"CardPwdList":[{"Card":"","Pwd":"ACTUAL_ALLOCATED_CARD"}]}OrderSn 是商城供货订单 ID;Amount 是元数值。卡池每行完整内容作为 Pwd,Card 可为空;Pwd 必须非空,条数等于采购数量。只有真实余额支付和卡密分配均完成,才返回成功。
已形成失败记录:
{"IsError":true,"Code":1,"Msg":"商城余额不足;本采购号已失败","OrderSn":"mall-supplier-order-id"}结果待确认:
{"IsError":true,"Code":1,"Msg":"采购结果待确认,请查询原订单,勿重复采购"}尚未形成结果时可能没有 OrderSn。当前商城兼容响应的成功码是 10000,失败使用 Code=1 和明确 Msg,并非 Agiso 的完整错误码表。正常进入协议 handler 的业务错误也可能是 HTTP 200,必须检查响应字段。
完整 Node.js 查询示例
下列 agiso-client.mjs 使用 Node.js 18+ 内置模块,默认只查第一页商品,不采购。把凭据配置在服务端环境变量中。示例导出的函数也可供您的服务端调用采购接口;一旦调用 purchase 将可能真实扣款。
import { createHash } from 'node:crypto';
import { pathToFileURL } from 'node:url';
export function agisoSign(secret, params) {
const middle = Object.keys(params).filter(key => key !== 'sign').sort()
.map(key => key + String(params[key])).join('');
return createHash('md5').update(secret + middle + secret, 'utf8').digest('hex');
}
export async function callAgiso(action, fields) {
const { KST_MALL_BASE, AGISO_CLIENT_SECRET, AGISO_ACCESS_TOKEN } = process.env;
if (!KST_MALL_BASE || !AGISO_CLIENT_SECRET || !AGISO_ACCESS_TOKEN) {
throw new Error('缺少商城地址、ClientSecret 或 access_token');
}
if (!['categoryList', 'purchase'].includes(action)) throw new Error('接口方法无效');
const base = new URL(KST_MALL_BASE);
if (base.protocol !== 'https:' || base.username || base.password) {
throw new Error('商城地址必须使用 HTTPS');
}
const params = {
...fields,
access_token: AGISO_ACCESS_TOKEN,
timestamp: String(Math.floor(Date.now() / 1000))
};
params.sign = agisoSign(AGISO_CLIENT_SECRET, params);
const raw = new URLSearchParams(params).toString();
if (Buffer.byteLength(raw) > 65536) throw new Error('请求体超过 64 KiB');
const response = await fetch(new URL('/supplier/agiso/api/' + action, base), {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: raw,
signal: AbortSignal.timeout(20000),
redirect: 'error'
});
let result;
try { result = await response.json(); }
catch { throw new Error(`HTTP ${response.status}:响应不是合法 JSON,请核对原采购号`); }
if (!response.ok || result?.IsError !== false || result?.Code !== 10000) {
const error = new Error(result?.Msg || `HTTP ${response.status}:供货请求失败`);
error.orderSn = result?.OrderSn;
throw error;
}
return result;
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
callAgiso('categoryList', { key_word: '', page_no: '1', page_size: '20' })
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(error => {
console.error(error.message, error.orderSn || '');
process.exitCode = 1;
});
}Windows PowerShell:
$env:KST_MALL_BASE = 'https://您的商城域名'
$env:AGISO_CLIENT_SECRET = '平台确认的ClientSecret'
$env:AGISO_ACCESS_TOKEN = '本次授权换得的Token'
node agiso-client.mjs签名函数的离线校验值:agisoSign('test-secret', {tid:'1234567890', timestamp:'1700000000'}) 应为 2d05dff081282634ca6153ee376b33af。这只是算法校验,不是一个完整采购请求。
重试、失败与查单
稳定业务键由租户、渠道、绑定会员、分站及 tid、oid、type 组成。商品编码 cpc_id、数量 num 参与请求一致性校验。同键换商品或数量会拒绝;重复请求不会再创建订单、再扣余额或重新分配卡密。
不同 type 是不同业务键。 不得把 Pay 改成 Confirm 或其他值来重试同一次采购。
| 情况 | 正确处理 |
|---|---|
| 请求超时、响应损坏或结果待确认 | 保留原 tid/oid/type/cpc_id/num,只更新 timestamp/sign,重试同一 purchase 读取原结果;或请管理员查询原订单 |
| 明确提示余额不足、本采购号已失败 | 补足余额后同号不会重启支付;先核对订单和钱包,再决定是否使用新业务号采购 |
| 已付款但卡密未返回 | 查询原结果,排查履约;不要再买一单补偿 |
| 授权无效或网关关闭 | 检查网关、会员状态、独立渠道供货权限、绑定站点、授权有效期;重新授权后更新凭据 |
| 请求过于频繁 | 降低频率、等待后用新时间戳签名;不要立即循环重试 |
余额支付前失败可能留下商城待付款订单,由原有超时流程关闭。不要在会员中心手动补付已失败的供货订单,否则外部平台的原失败记录不会因此重新执行采购。
商品实名、购买策略、站点范围和风控仍生效。商城 order 场景要求逐单交易密码时,本协议没有密码字段,会员授权和自动采购会拒绝执行。不要为了“接通”而宣称这些条件可以绕过。
商城运行授权失效或版本停用会阻止新采购;原已付款订单保留查单善后能力,但渠道网关、商户授权、会员状态、渠道权限和站点仍需有效。撤销授权或关闭网关不能保证外部查单继续可用。
对账与售后
- 后台「电商渠道供货 → 采购订单」可搜索采购号、供货订单 ID、会员,查看状态和失败原因,点击「查询原订单」。每次最多读取 200 笔,不是全部历史订单查询承诺。
OrderSn是商城供货订单 ID,也是该笔商城订单 ID;商城展示订单号为CS加此 ID。失败记录里的金额不是已经扣款的证明。- 会员「我的订单」核对付款和交付,「资金中心」核对钱包流水;工单提交商城订单号、外部
tid/oid/type和问题,不提交密钥或完整卡密。
/pc/#orders
/pc/#funds
/support/当前没有 Agiso 协议退款入口。售后通过商城工单和实际订单退款流程处理:申请不等于已退款,订单退款处理中不对外返回卡密;已交付卡密不能确认退款,已退款订单不能再分配卡密。符合条件的余额订单确认退款后退回原商城会员余额,不会通过本接口自动退还外部买家的平台付款。
真实联调边界
本说明和本地测试不能证明已取得 Agiso 供应商资格、通过官方审核或跑通真实店铺交易。接入方仍需取得 SupplierId、ClientId、ClientSecret、测试店铺及确认过的 HTTPS 回调,核对授权回跳、UTC 到期时间解析、type 使用和平台失败重试行为,完成真实订单与资金对账。
平台资料供对照,平台当前规则以实际确认结果为准: