API reference
External programs use this API to pull products, check stock, get quotes, place orders and query them. The store sharing feature is itself built on it.
If you only want to resell someone's products without writing code, use store sharing in the admin panel. This page is for people writing their own integration.
Before you start:
- Register on the target store and collect your merchant ID (
app_id) and merchant key (app_key) from User centre → My profile - Their products must have API access enabled, or you cannot see them
- The prices you get depend on your member tier on their store
Basics
- Method:
POST - Format:
application/x-www-form-urlencodedrecommended - Authentication: the common parameters
app_id+sign - Success:
code = 200 - Failure: usually
code = 0, with the reason inmsg
Signing
/**
* Generate the request signature
* @param array $data
* @param string $appKey
* @return string
*/
public static function generateSignature(array $data, $appKey): string
{
unset($data['sign']);
ksort($data);
foreach ($data as $key => $val) {
if ($val === '') {
unset($data[$key]);
}
}
return md5(urldecode(http_build_query($data) . "&key=" . (string)$appKey));
}Common request parameters
| Name | Required | Type | Description |
|---|---|---|---|
| app_id | yes | string/int | Merchant ID, from your profile in the user centre |
| sign | yes | string | All POST parameters of this request signed with the algorithm above |
app_keyis your merchant key. It is only used locally to generate the signature and should never be sent to the other server.If the request contains array parameters such as
sku, they must take part in the signature too, and the signed content must match exactly what you actually submit.
Common response format
| Field | Type | Description |
|---|---|---|
| code | int | Status code; 200 on success |
| msg | string | Message. Optional — only returned when the controller sets it explicitly |
| data | mixed | Payload |
Success:
{
"code": 200,
"data": {}
}Failure:
{
"code": 0,
"msg": "Invalid key"
}Business fields
race— product variant, matching a key under[category]in the product configuration, e.g.Monthly,Yearlysku— SKU combination; submit as an array, e.g.sku[Colour]=Black&sku[Capacity]=256GBcard_id— pre-selected card ID; only meaningful when the product detail reportsdraft_status=1widget— custom widgets; if the product detail returnswidget, submit each widget'snameas a request parameter when orderingrequest_no— idempotency key. Not strictly enforced by the code, but strongly recommended on every order to avoid duplicates
List all products
POST /shared/commodity/items
- Body: no business parameters, just
app_idandsign
data is an array of categories, each with a children array of products:
| Field | Type | Description |
|---|---|---|
| id | int | Category or product ID |
| name | string | Category or product name |
| children | array | Products available in this category |
| code | string | Product code, used by the detail and order endpoints |
| price | string/float | Guest price |
| user_price | string/float | Member / reseller price |
| stock | int | Stock, for automatic-delivery products |
| delivery_way | int | Delivery method |
| draft_status | int | Whether buyer-selectable stock is supported |
Product detail
POST /shared/commodity/item
| Name | Required | Type | Description |
|---|---|---|---|
| code | yes | string | Product code |
Core fields of data:
| Field | Type | Description |
|---|---|---|
| id | int | Product ID |
| name | string | Product name |
| description | string | Product description |
| code | string | Product code |
| price | string/float | Guest price |
| user_price | string/float | Member / reseller price |
| stock | int/string | Current stock |
| delivery_way | int | Delivery method |
| contact_type | int | Contact type: 0=any, 1=phone, 2=email, 3=QQ |
| password_status | int | Query password enabled: 0=no, 1=yes |
| draft_status | int | Buyer-selectable stock: 0=no, 1=yes |
| draft_premium | string/float | Surcharge for pre-selection |
| minimum | int | Minimum quantity, 0 for no limit |
| maximum | int | Maximum quantity per order, 0 for no limit |
| config | object | Parsed product configuration, typically containing category, sku, wholesale |
| widget | array/null | Custom widget definitions; submit each widget's name when ordering |
| seckill_status | int | Whether this is a flash-sale product |
| seckill_start_time | string | Flash sale start |
| seckill_end_time | string | Flash sale end |
| owner | object | Supplier information |
| service_url | string | Support link |
| service_qq | string | Support QQ |
| share_url | string | Shareable product link |
Check whether stock allows an order
POST /shared/commodity/inventoryState
| Name | Required | Type | Description |
|---|---|---|---|
| shared_code | yes | string | Product code |
| num | yes | int | Quantity |
| card_id | no | int | Pre-selected card ID; 0 or omitted when not pre-selecting |
| race | no | string | Product variant |
A successful response means current stock (or the pre-selected card) satisfies the order:
{
"code": 200,
"msg": "success",
"data": []
}Insufficient stock, an unknown product, a discontinued product or an already-taken pre-selected card all return a failure instead.
Stock and basic configuration
POST /shared/commodity/inventory
| Name | Required | Type | Description |
|---|---|---|---|
| sharedCode | yes | string | Product code |
| race | no | string | Product variant; the default variant is used when omitted |
| Field | Type | Description |
|---|---|---|
| count | int | Current stock |
| delivery_way | int | Delivery method |
| draft_status | int | Whether pre-selection is supported |
| price | string/float | Base price |
| user_price | string/float | Member price |
| config | string | Product configuration, returned as raw INI text |
| factory_price | string/float | Your cost price under the current integration identity |
| is_category | bool | Whether this is a variant product |
Note:
confighere is configuration text, not the parsed object thatitemreturns.
Live stock
POST /shared/commodity/stock
| Name | Required | Type | Description |
|---|---|---|---|
| code | yes | string | Product code |
| race | no | string | Product variant |
| sku | no | array | SKU combination |
{
"code": 200,
"data": {
"stock": "15"
}
}Quote
POST /shared/commodity/valuation
| Name | Required | Type | Description |
|---|---|---|---|
| code | yes | string | Product code |
| num | yes | int | Quantity |
| race | no | string | Product variant |
| sku | no | array | SKU combination |
| card_id | no | int | Pre-selected card ID |
{
"code": 200,
"data": {
"price": "99.00"
}
}List pre-selectable cards
POST /shared/commodity/draftCard
| Name | Required | Type | Description |
|---|---|---|---|
| code | yes | string | Product code |
| page | recommended | int | Page number, starting at 1 |
| limit | no | int | Page size, default 10 |
| race | no | string | Product variant |
| sku | no | array | SKU combination |
| Field | Type | Description |
|---|---|---|
| list | array | Cards |
| total | int | Total count |
| list[].id | int | Card ID |
| list[].draft | string | Preview text |
| list[].draft_premium | string/float | Surcharge for this card |
Only available when the product detail reports
draft_status=1.
Single pre-selected card
POST /shared/commodity/draft
| Name | Required | Type | Description |
|---|---|---|---|
| code | yes | string | Product code |
| card_id | yes | int | Card ID |
| Field | Type | Description |
|---|---|---|
| draft_premium | string/float | Surcharge for this card |
Place an order
POST /shared/commodity/trade
This endpoint always pays from your balance.
| Name | Required | Type | Description |
|---|---|---|---|
| shared_code | yes | string | Product code |
| num | yes | int | Quantity |
| request_no | no | string | Idempotency key; a unique value per order is strongly recommended |
| contact | no | string | Contact; a placeholder value is fine |
| race | no | string | Product variant |
| sku | no | array | SKU combination |
| card_id | no | int | Pre-selected card ID |
| password | no | string | Query password |
| coupon | no | string | Coupon code |
| device | no | int | Device type; 0 when you do not distinguish |
If the product detail returned
widget, also submit each widget'snameas an additional parameter.
| Field | Type | Description |
|---|---|---|
| tradeNo | string | Order number |
| amount | string/float | Amount actually charged |
| secret | string/null | Delivery content; for manual delivery this may be a "pending" message |
| stock | string/int | Remaining stock after the order |
{
"code": 200,
"msg": "success",
"data": {
"url": null,
"amount": "10.00",
"tradeNo": "123260422101010888",
"secret": "card key content",
"stock": "14"
}
}Query an order
POST /shared/commodity/query
| Name | Required | Type | Description |
|---|---|---|---|
| tradeNo | yes | string | Order number — note the field is tradeNo, not trade_no |
| Field | Type | Description |
|---|---|---|
| secret | string | Delivery content or card key |
| widget | object/null | Widget values submitted with the order |
| status | int | Payment status: 0=unpaid, 1=paid |
Suggested integration flow
- Call
itemsoritemto pull product information - If the product has
categoryorsku, determineraceandskufirst - If it supports pre-selection, call
draftCardfor the options anddraftfor the surcharge when needed - Before ordering, confirm stock and price with
stock,valuationorinventoryState - Call
tradeto place the order - Poll
queryif you need to track delivery
Notes
- To test authentication only, call
/shared/authentication/connect - The product detail endpoint returns
configas a parsed object whileinventoryreturns it as INI text. That is not a documentation error — it is how the program currently behaves - If you want full compatibility with the built-in sharing client, follow the field names and response shapes in this document; do not rename
tradeNototrade_noand so on
