如何通过 API 将自定义商店接入 easySales
通过 API 把任意自定义或尚未支持的商店平台接入 easySales:需要的两个凭据、推送产品与库存、送入订单,以及把变化取回去。
什么时候需要这么做
easySales 为常见的商店平台提供现成的连接器。如果你用的是自定义的东西——自研的店铺,或者我们还没有做集成的平台——你可以自己通过 API 把它接进来。
这是一项开发工作。你要写代码把自己的商品目录推送到 easySales 并把订单送过来,而 easySales 会在有变化时回调你的店铺。这里的任何一步都不需要安装插件。
连接是怎么运作的
这里涉及两个凭据,把它们弄混是第一次集成返回 403 最常见的原因。
| 凭据 | 从哪里来 | 如何发送 | 缺失时 |
|---|---|---|---|
| 访问令牌 |
POST /oauth/token,使用你在 API设置 中创建的 OAuth 客户端
|
Authorization: Bearer <token> 请求头
|
401 |
| 网站令牌 | 连接向导的配置步骤 |
请求体中的 website_token 字段,不是请求头
|
403 Invalid website token |
每一次写入都需要两个。访问令牌证明是谁在调用;网站令牌说明数据属于哪家店铺。
第 1 步 — 添加网站
进入整合方式 → 网站,点击连结网站,填写表单,然后选择 API 图块以及它下面的 API V2 版本。
| 字段 | 作用 |
|---|---|
| 网站名称 | 你自己的标签。以后靠它区分不同的店铺。 |
| 网址 | 你的店铺地址,带上正确的协议。 |
| 国家 | 决定下一个字段提供哪些增值税税率。不可更改。 |
| 增值税价格 | 对未带税率的产品所应用的增值税。从列表中选择,不能手输。 |
| 运输增值税 | 订单未带税率时,对配送所应用的增值税。 |
| 语言 / 货币 | 店铺的语言,以及你的价格所使用的货币。两者都不可更改。 |
| 新订单自定义状态 | 可选。让每一笔导入的订单落到你自己的某个状态里。 |
| 库存来源 | 权威库存数值所在的位置。默认是 easySales。 |
| 隐式封装类型 | 为这些订单生成运单时使用的默认值。 |
| 发票系列 | 当你的请求没有提供发票系列时所使用的开票系列。 |
第 2 步 — 复制网站令牌
向导的配置步骤会显示一个 60 个字符的令牌。旧文章从未提到过它,而每一次写入调用都需要它。
用按钮复制,不要手动重打,并把它作为机密保存在你的应用里。点击保存创建网站。
店铺现在会出现在整合方式 → 网站下,卡片上带着同一个令牌——以后就到那里再找它。
第 3 步 — 创建 OAuth 客户端
进入设定值 → API设置。OAuth 凭据就在这里。
点击创建新客户,按将要发起调用的系统给它命名,并把授权类型设为 Website Grant。
Website Grant 正是为这件事而设计的:它用你的网站令牌换取访问令牌,不需要浏览器跳转,也不需要用户操作。保存后复制出现的客户 ID 和密钥。
第 4 步 — 获取访问令牌
POST https://easy-sales.com/oauth/token
Content-Type: application/json
{
"grant_type": "website",
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"website_token": "your-60-character-website-token",
"scope": "add-products update-products update-stock add-orders update-orders read-orders"
}
返回的是标准的 OAuth 响应体:
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "eyJ0eXAiOiJKV1Qi...",
"refresh_token": "def50200a1b2c3..."
}
在之后的每一次调用中,把它作为 Authorization: Bearer <access_token> 发送。
第 5 步 — 推送你的商品目录
下面所有请求的基础地址是 https://easy-sales.com/api/v2。
顺序很重要。 类别和特性必须先存在,产品才能引用它们,否则产品调用会被拒绝。
POST /categories/save— 你的类别POST /characteristics/save— 你的属性POST /products/save— 你的产品
POST https://easy-sales.com/api/v2/products/save
Authorization: Bearer <access_token>
Content-Type: application/json
{
"website_token": "your-60-character-website-token",
"product": {
"product_website_id": "10231",
"sku": "TS-BLK-M",
"name": "Black T-shirt, size M",
"sale_price": 79.99,
"full_price": 99.99,
"stock": 24,
"type": "simple",
"tax_rate": 21,
"url": "https://my-shop.example.com/p/ts-blk-m",
"images": ["https://my-shop.example.com/img/ts-blk-m.jpg"],
"categories": ["cat-778"],
"characteristics": [{ "id": "char-12", "value": "Black" }]
}
}
| 字段 | 是否必填 | 说明 |
|---|---|---|
product_website_id
|
是 | 该产品在你店铺中的自有 ID |
sku
|
是 | 在每个网站内唯一;upsert 的主键 |
name
|
是 | |
sale_price
|
是 | 客户实际支付的价格 |
stock
|
是 | 必须是数字 |
type
|
是 |
simple 或 complex
|
full_price
|
否 | 折扣前价格,如果你会展示的话 |
tax_rate
|
否 | 必须是该网站所属国家的有效税率 |
categories
|
否 | 你自己的类别 ID——每一个都必须已经存在 |
characteristics
|
否 | 你自己的属性 ID——每一个都必须已经存在 |
images
|
否 | 我们可以抓取的 URL 数组 |
weight, handling_time, description, url
|
否 | 用于快递、配送时效估算和市场平台刊登 |
第 6 步 — 保持库存同步
库存是必须保持最新的那一项,而且它是最适合频繁调用的低成本接口。每次最多发送 100 行:
PATCH https://easy-sales.com/api/v2/stocks/bulk
Authorization: Bearer <access_token>
{
"website_token": "your-60-character-website-token",
"data": [
{ "sku": "TS-BLK-M", "stock": 24 },
{ "sku": "TS-BLK-L", "stock": 0 }
]
}
每个 SKU 都必须已经存在于这个网站上;未知的会被拒绝,而不会被创建。
第 7 步 — 把订单送进来
POST https://easy-sales.com/api/v2/orders/save
Authorization: Bearer <access_token>
{
"website_token": "your-60-character-website-token",
"order": {
"order_id": "SO-100244",
"order_date": "2026-09-09 14:31:00",
"order_total": 179.98,
"status": "new",
"payment_mode": "card",
"shipment_tax": 21,
"billing_address": { "country": "RO", "city": "Cluj-Napoca", "street": "Str. Memorandumului 4" },
"shipping_address": { "country": "RO", "city": "Cluj-Napoca", "street": "Str. Memorandumului 4" },
"order_products": [
{ "product_website_id": "10231", "sku": "TS-BLK-M", "name": "Black T-shirt, size M",
"quantity": 2, "price": 79.99, "total": 159.98 }
]
}
}
再次提交相同的 order_id,订单会被更新而不是重复创建,这让重试是安全的。
第 8 步 — 把变化取回去
你的店铺需要知道订单何时开了发票、生成了运单或改变了状态。订阅一个 webhook,而不是轮询:
GET https://easy-sales.com/api/v2/webhooks
Authorization: Bearer <access_token>
POST https://easy-sales.com/api/v2/webhooks/order-updated
Authorization: Bearer <access_token>
{
"url": "https://my-shop.example.com/hooks/easysales",
"secret": "a-shared-secret-of-at-least-24-characters"
}
每次只能订阅一个事件,因此需要对 order-created、order-updated、awb-created、invoice-created 和 delivery-status-updated 分别调用一次。
每一次推送都有签名,所以在信任内容之前先校验签名。要快速响应——请求会在几秒后超时,并且只会重试有限的次数,所以先确认接收,再去处理。
限制
| 限制项 | 数值 |
|---|---|
| 请求数 | 整个 API 每分钟 500 次 |
| 令牌请求 | 每分钟 60 次——请缓存你的令牌 |
| 每次批量调用的产品、库存、价格、类别、特性数量 | 100 |
| 每次批量归档调用的产品数量 | 50 |
| 每个账户的网站数量 | 30 |
| 产品描述 | 65,534 个字符 |
出错的时候
| 代码 | 含义 | 常见原因 |
|---|---|---|
| 400 |
Invalid json
|
请求体不是合法的 JSON |
| 401 | 未通过身份验证 | 访问令牌缺失、过期或格式错误 |
| 403 |
Invalid website token
|
website_token 缺失或错误
|
| 403 |
The website has been deactivated
|
网站的积极的开关处于关闭状态 |
| 422 | 校验失败 | 缺少必填字段、SKU 重复,或者类别、特性尚不存在 |
| 429 | 请求过多 | 超过每分钟 500 次 |
| 503 | 暂时不可用 | 数据接收出现积压;请在提示的间隔后重试 |
在我们这边失败的内容也会进入产品 → 网上商店 → 网站错误,附带请求内容和一个重试操作,这通常比重新复现调用更快。
参考文档
完整的接口参考,包含每个字段和每种响应,发布在 https://api.easy-sales.com。