Skip to Content
仓信AI / Cangxin AI Open API

仓信AI / Cangxin AI Open API v1 · Seller / ERP API

For your own system or ERP (Lingxing, Dianxiaomi, Mabang ...): create orders and inbound notices, query stock and tracking, and receive webhooks. Machine-readable spec: /api/v1/openapi.json (OpenAPI 3.1, import it into Postman / Apifox).

Base URL: https://cangxinai.com/api/v1

0. ERP integration (Lingxing) at a glance / ERP 对接要点(领星)

A test account is delivered as exactly three values: test domain, appKey and appSecret. Nothing else is needed to call the API.
测试账号只交付三项:测试域名、appKey、appSecret。调用接口不需要其他参数。

Lingxing field / 领星字段Our value / 我方对应Header / 请求头
API domain / API 域名 Base URL of the environment, ending in /api/v1 (production, or the separate test environment for a test account)
接口地址,以 /api/v1 结尾(正式环境;测试账号则为独立测试环境的地址)
-
appKey The seller code (GET /me returns it as key.appkey). Identifies the seller, not a secret
卖家代码(GET /me 返回的 key.appkey),用于识别卖家,不是密钥
X-WMS-Key
appSecret The API key (shown once when created; stored hashed). Sent as a Bearer token, or not sent at all when requests are signed with HMAC-SHA256 (optional)
API 密钥(生成时只显示一次,服务器只存哈希)。作为 Bearer 令牌发送;或可选用 HMAC-SHA256 请求签名,此时密钥本身不发送
Authorization: Bearer <appSecret> | X-WMS-Signature
curl https://cangxinai.com/api/v1/me \
  -H "X-WMS-Key: <appKey>" \
  -H "Authorization: Bearer <appSecret>"

Request signing is optional: see Signed requests. / 请求签名为可选项,见下文"请求签名"。

Lingxing functions and endpoints / 领星对接功能与接口对应
#Lingxing function / 领星功能Endpoints / 接口Webhooks / 推送
1 1. 基础对接(商品、仓库、库存、订单)
Base data: SKUs, warehouses, inventory, orders
GET /api/v1/skus
POST /api/v1/skus
PUT /api/v1/skus/{id}
GET /api/v1/warehouses
GET /api/v1/inventory
GET /api/v1/orders
GET /api/v1/orders/{id}
-
2 2. FBA 备货入库(入库预报)
FBA stock inbound: inbound notice (ASN) and received quantities
POST /api/v1/inbound
GET /api/v1/inbound
GET /api/v1/inbound/{id}
Related / 相关 (FBA replenishment, warehouse → Amazon / 仓库发往亚马逊 FBA):POST /api/v1/transfers GET /api/v1/transfers/{id}
inbound.received
3 3. 出库发货(推单、跟踪号回传、截单)
Outbound: push orders, tracking number back, cancel / intercept
POST /api/v1/orders
GET /api/v1/orders/{id}
GET /api/v1/orders/by-external/{external_id}
POST /api/v1/orders/{id}/cancel
POST /api/v1/orders/{id}/hold
order.label_created
order.shipped
4 4. 退件入库
Returns: announce a return, inspection result, instruction
POST /api/v1/returns
GET /api/v1/returns
GET /api/v1/returns/{id}
POST /api/v1/returns/{id}/instruction
return.awaiting_instruction

Tracking numbers: GET /orders/{id} returns carrier and tracking_numbers as soon as the warehouse buys the label. / 跟踪号:仓库买面单后,GET /orders/{id} 即返回 carrier 和 tracking_numbers。

PDF version (Chinese) / 下载中文 PDF 版

1. Authentication

The seller creates an API key in the seller portal (API page, login required; only the seller account owner can create keys) and gives it to the system that calls the API. Requests run with that seller's permissions: only the seller's own data in its contracted warehouses.

curl https://cangxinai.com/api/v1/warehouses \
  -H "Authorization: Bearer <API_KEY>"

appkey / appSecret: for ERPs that ask for two values, appkey is the seller code (key.appkey in the GET /me answer; it identifies the seller and is not secret) and appSecret is the API key. With Bearer authentication the appkey may also be sent in the X-WMS-Key header; it must then match the key's seller, otherwise the answer is 401 appkey_mismatch.

Signed requests (optional)

Instead of sending the key, sign every request. Headers: X-WMS-Key (appkey, or the key prefix), X-WMS-Timestamp (Unix seconds; accepted within 300 seconds of our clock), X-WMS-Nonce (8-64 characters [A-Za-z0-9_-], never reused for the same key) and X-WMS-Signature. Errors: 401 invalid_signature, signature_expired, nonce_reused.

import hashlib, hmac, secrets, time

def sign(app_secret: str, method: str, path: str, query: str, body: bytes) -> dict:
    # path and query exactly as sent, e.g. "/api/v1/orders" and "status=pending&page=1"
    timestamp, nonce = str(int(time.time())), secrets.token_hex(16)
    message = "\n".join([method.upper(), path, query, timestamp, nonce,
                         hashlib.sha256(body).hexdigest()])
    key = hashlib.sha256(app_secret.encode()).hexdigest()   # signing key = sha256_hex(appSecret)
    signature = hmac.new(key.encode(), message.encode(), hashlib.sha256).hexdigest()
    return {"X-WMS-Key": "<appkey>", "X-WMS-Timestamp": timestamp,
            "X-WMS-Nonce": nonce, "X-WMS-Signature": "sha256=" + signature}

Per key, the seller can also require signed requests (Bearer then answers 401 signature_required) and set an IP allow-list (other addresses get 403 ip_not_allowed).

ScopeGrants
ordersOutbound orders and FBA / transfer orders
inboundInbound notices (ASN) and SKU master data
stockInventory and SKU read access
returnsReturn announcements and instructions
vasValue-added service requests
billing:readPrepaid balance, transactions and charges (read only)

2. Conventions

  • JSON in and out, UTF-8. Dates are ISO 8601 in UTC (2026-11-10T08:00:00Z).
  • Lists: ?page=1&page_size=50 (max 200) → {"data": [...], "pagination": {...}}.
  • Errors: {"error": {"code": "...", "message": "...", "details": {...}}} with HTTP 400 / 401 / 403 / 404 / 409 / 422 / 429. Records of other sellers answer 404.
  • On POST, send an Idempotency-Key header with a unique value (for example your order number): a retry with the same key and body within 7 days returns the first response (header Idempotent-Replayed: true) and creates nothing twice.
  • Rate limit per key (default 120 requests / minute): see X-RateLimit-* headers; HTTP 429 comes with Retry-After.
  • Add Accept-Language: zh-CN to get error messages in Chinese.
  • Warehouses: GET /warehouses returns each contracted warehouse with its public_code (e.g. WS-ACME-LAX1): unique on the whole platform and never changed. Use it as warehouse_code (or send warehouse_id). The short code is unique per warehouse company only: when two contracted warehouses share it, the API answers 422 ambiguous_warehouse_code.

3. Endpoints

MethodPathScopeDescription
GET /api/v1/me - Current API key, user and seller
GET /api/v1/warehouses - Contracted warehouses
GET /api/v1/skus stock, inbound, orders List SKUs
GET /api/v1/skus/{id} stock, inbound, orders Get a SKU
POST /api/v1/skus inbound Create a SKU
PUT /api/v1/skus/{id} inbound Update a SKU (only the fields sent)
POST /api/v1/orders orders Create an outbound order
GET /api/v1/orders orders List outbound orders
GET /api/v1/orders/{id} orders Order status and tracking
POST /api/v1/orders/{id}/cancel orders Cancel an order (before picking starts)
POST /api/v1/orders/{id}/hold orders Ask the warehouse to hold / intercept an order
GET /api/v1/orders/by-external/{external_id} orders Order status and tracking, by your order number
POST /api/v1/orders/by-external/{external_id}/cancel orders Cancel an order by your order number (before picking starts)
POST /api/v1/orders/by-external/{external_id}/hold orders Hold / intercept an order by your order number
POST /api/v1/inbound inbound Create an inbound notice (ASN)
GET /api/v1/inbound inbound List inbound notices
GET /api/v1/inbound/{id} inbound Inbound notice status and received quantities
GET /api/v1/inventory stock Stock by warehouse / SKU / batch
POST /api/v1/returns returns Announce a return
GET /api/v1/returns returns List returns
GET /api/v1/returns/{id} returns Get a return
POST /api/v1/returns/{id}/instruction returns Give the instruction for an inspected return
GET /api/v1/vas/services vas Services that can be requested
POST /api/v1/vas vas Request a value-added service
GET /api/v1/vas vas List value-added service requests
GET /api/v1/vas/{id} vas Get a value-added service request
POST /api/v1/transfers orders Create an FBA / transfer order (box labels as base64 PDF)
GET /api/v1/transfers orders List FBA / transfer orders
GET /api/v1/transfers/{id} orders Get an FBA / transfer order
GET /api/v1/wallets billing:read Prepaid balance per warehouse company
GET /api/v1/wallets/{id}/transactions billing:read Prepaid balance transactions
GET /api/v1/charges billing:read Charges (billable events)
Create an order

The order goes through the same pipeline as uploaded order files: SKUs are matched by SKU code, barcode or your SKU mappings; the same external_id twice answers 409.

curl -X POST https://cangxinai.com/api/v1/orders \
  -H "Authorization: Bearer <API_KEY>" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 111-1234567-1234567" \
  -d '{"warehouse_code": "WS-ACME-LAX1", "external_id": "111-1234567-1234567", "channel": "amazon",
       "ship_by_date": "2026-11-12T07:59:59Z",
       "recipient": {"name": "Jane Smith", "street": "1 Main St", "city": "Los Angeles",
                     "state": "CA", "zip": "90001", "country": "US", "phone": "555-0100"},
       "lines": [{"sku": "MUG-01", "quantity": 2, "external_item_id": "10000000000001"}]}'

Then poll GET /orders/{id} or GET /orders/by-external/{external_id} (status pending → processing → shipped, with tracking_numbers), or subscribe to the order.label_created / order.shipped webhooks. Cancel or hold by your own order number with POST /orders/by-external/{external_id}/cancel and /hold (URL-encode it; order numbers containing "/" must use the numeric id).

4. Webhooks

Register HTTPS URLs on the seller portal API page. We POST a JSON event; answer any 2xx within 10 seconds. Failed deliveries are retried after 1, 5, 15, 60 minutes, 3, 6, 12 and 24 hours (8 attempts), and are listed with their result on the API page. Events may arrive more than once: ignore an id you have already processed.

EventWhen
order.label_createdA shipping label was bought: first tracking number, before the order leaves the warehouse
order.shippedAn order or transfer left the warehouse (tracking numbers included)
order.heldAn order was put on hold
inbound.receivedGoods of an inbound notice were received
return.awaiting_instructionAn inspected return waits for your instruction
wallet.low_balanceA prepaid balance fell below its low-balance threshold

order.label_created is sent once per order and tracking number, as soon as the warehouse buys the label (before the parcel leaves); order.shipped follows when it leaves.

POST https://erp.example.com/wms/webhook
X-WMS-Event: order.shipped
X-WMS-Timestamp: 1762761600
X-WMS-Signature: sha256=5d41402abc4b2a76b9719d911017c592...

{"id": "evt_...", "type": "order.shipped", "created_at": "2026-11-10T08:00:00Z",
 "seller": {"id": 7, "code": "S001"},
 "data": {"order": {"id": 42, "external_id": "111-1234567-1234567", "status": "shipped",
                    "carrier": "UPS", "tracking_numbers": ["1Z999AA10123456784"], ...}}}

Verify the signature (HMAC-SHA256 of timestamp + "." + raw body with your endpoint secret) and reject old timestamps:

import hashlib, hmac, time

def verify(secret: str, headers: dict, raw_body: bytes) -> bool:
    timestamp = headers["X-WMS-Timestamp"]
    if abs(time.time() - int(timestamp)) > 300:
        return False
    expected = hmac.new(secret.encode(), timestamp.encode() + b"." + raw_body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest("sha256=" + expected, headers["X-WMS-Signature"])