Open Platform (Open API) Integration Guide
Online docs (recommended): https://docs.rizzitgo.com — API reference stays in sync with this guide
Audience: external partners / third-party developers
Languages: English (this document) · 中文
This guide explains how to integrate with our /open-api/* open endpoints. The open endpoints are physically isolated from the consumer-facing /app-api and the admin /admin-api. They use OAuth2 client_credentials (client mode) for authentication, and control the set of callable endpoints per application via scope.
1. Overview and Architecture
- Auth model: standard OAuth2 client-credentials mode. Partners exchange the issued
clientId + clientSecretfor a short-livedaccess_token, then call business endpoints with that token. The open platform does not involve user login, authorization-code, or password grants. - Endpoint isolation: all open endpoints live under the
/open-api/**prefix and are routed separately by the gateway. Open tokens have a fixed user type ofOPEN_APIand cannot access/admin-apior/app-api, eliminating privilege escalation at the source. - Permission granularity: each endpoint is guarded by the
scopeit requires (e.g. the goods-detail endpoint requiresgoods:detail:read). An application can only call endpoints corresponding to the scopes granted to it. - Multi-tenancy: requests must carry
tenant-id, which must match the one used when the token was obtained.
Call sequence:
sequenceDiagram
participant P as Partner App
participant GW as API Gateway
participant SYS as System Service
participant BIZ as Business Service
P->>GW: POST /open-api/system/oauth2/token<br/>Basic(clientId:clientSecret)
GW->>SYS: forward token request
SYS-->>P: access_token (userType=OPEN_API, expires_in)
P->>GW: POST /open-api/goods/detail<br/>Bearer access_token + tenant-id
GW->>BIZ: validate token + scope, then forward
BIZ-->>P: business data (unified {code,data,msg})
2. Glossary
| Term | Description |
|---|---|
clientId |
Client ID, the public identifier of the application. |
clientSecret |
Client secret, shown only once at creation/reset. Treat it like a password and keep it secret. |
scope |
Authorization scope; determines which endpoints can be called. Multiple values are space-separated (e.g. goods:detail:read). |
tenant-id |
Tenant ID, the multi-tenant isolation identifier, passed as a request header. |
access_token |
Access token, the credential for calling business endpoints; time-limited (see expires_in). |
externalUserId |
Partner-side user id. Must be bound to a platform member in Admin Console "Open Platform / Member Bind" before quote, create, or wallet pay. |
outOrderNo |
Partner order number, unique per clientId; used for create-order idempotency. |
paymentId |
Platform payment id returned by purchase create or supplement/trade-no; pass it to wallet pay. |
expires_in |
Remaining token lifetime, in seconds. |
userType |
User type; always OPEN_API for open-platform tokens. |
3. Onboarding Process
- Contact platform operations and submit: partner name, contact (name / email / phone), source IPs for callbacks (optional, for the IP whitelist), and the required scopes.
- Operations creates the application under Admin Console "Open Platform / Partner Applications" and issues:
clientIdclientSecret(shown only once; store it securely)- the granted
scopelist (e.g.goods:detail:read) tenant-id
- The partner exchanges
clientId + clientSecretfor anaccess_token, then calls business endpoints with the token.
Pre-launch checklist:
-
clientSecretstored securely (recommended: a secrets manager; never embed in frontend/client code or logs). - All required
scopes confirmed as granted. - Caller egress IP added to the whitelist (if operations enabled the whitelist).
- Token caching implemented (reuse within
expires_in; do not fetch a token on every request). - Auto re-fetch on
401and exponential backoff retry on429implemented.
3.1 Complete Scope Reference
Below is the full list of available scope values. Naming convention: {domain}:{resource}:{action}. When requesting a token, specify the required scopes via the scope parameter (space-separated). Endpoints corresponding to scopes not granted to your application will return 403.
| # | Scope | Description | Endpoint(s) |
|---|---|---|---|
| 1 | goods:detail:read |
Read goods detail | POST /open-api/goods/detail |
| 2 | goods:qc:read |
Read goods QC data | POST /open-api/goods/qc-detailPOST /open-api/goods/qc-imagesPOST /open-api/goods/qc-page |
| 3 | goods:search:read |
Search goods | POST /open-api/goods/search-by-imagesPOST /open-api/goods/search-url-parse |
| 4 | promotion:redeem-code:redeem |
Redeem coupon code | POST /open-api/promotion/redeem-code/redeem |
| 5 | promotion:member-coupon:read |
Query member coupons | POST /open-api/promotion/member-coupon/page |
| 6 | promotion:member-coupon:extend |
Extend member coupons | POST /open-api/promotion/member-coupon/extend |
| 7 | promotion:member-coupon:restore |
Restore expired coupons | POST /open-api/promotion/member-coupon/restore |
| 8 | promotion:coupon-exchange-code:read |
Query coupon exchange code status | POST /open-api/promotion/coupon-exchange-code/status |
| 9 | promotion:spreadsheet:read |
Query promoter spreadsheet products | POST /open-api/promotion/spreadsheet/page |
| 10 | pay:order:create |
Create payment order | POST /open-api/pay/order/create |
| 11 | pay:order:query |
Query payment orders | POST /open-api/pay/order/queryPOST /open-api/pay/order/page |
| 12 | pay:order:shipments |
Upload shipment info | POST /open-api/pay/order/upload-shipments |
| 13 | pay:exchange-rate:read |
Read system exchange rate list | POST /open-api/pay/exchange-rate/list |
| 14 | order:bag-order:read |
Query bag orders | POST /open-api/order/bag-order/queryPOST /open-api/order/bag-order/page |
| 15 | order:order-item:read |
Query order item details | POST /open-api/order/order-item/page |
| 16 | logistics:track:query |
Query logistics tracking | POST /open-api/logistics/track/query |
| 17 | logistics:freight-estimate:read |
Freight estimate | POST /open-api/logistics/line/freight-estimate |
| 18 | member:auth:discord-login |
Get Discord OAuth login URL / login status | POST /open-api/member/auth/discord-authorize-urlPOST /open-api/member/auth/discord-login-status |
| 19 | system:partner-member:read |
Query partner-member bind | POST /open-api/system/partner-member/queryPOST /open-api/system/partner-member/list |
| 20 | order:purchase:quote |
Purchase-order quote | POST /open-api/order/purchase/quote |
| 21 | order:purchase:create |
Create purchase order | POST /open-api/order/purchase/create |
| 22 | order:purchase:query |
Query purchase order / supplement list | POST /open-api/order/purchase/queryPOST /open-api/order/purchase/supplement/list |
| 23 | order:purchase:supplement-pay |
Create supplement pay order | POST /open-api/order/purchase/supplement/trade-no |
| 24 | pay:wallet:query |
Query member wallet balance | POST /open-api/pay/wallet/balance |
| 25 | pay:wallet:pay |
Debit member wallet | POST /open-api/pay/wallet/pay |
| 26 | member:consumption:read |
Query member consumption | POST /open-api/member/consumption/query |
Note: The OAuth2 token endpoints (
/open-api/system/oauth2/tokenand/token/revoke) do not require any scope — they only needclientId + clientSecretauthentication. The scope list expands as new business capabilities are added; always refer to the latest version of this document.
4. Environments and Domains
| Environment | Gateway domain | Notes |
|---|---|---|
| Sandbox / Test | api-qa.rizzitbuy.com |
For integration testing; data isolated from production. |
| Production | api.rizzitgo.com |
Live environment. |
The production gateway domain is
api.rizzitgo.com(already used in the examples), and the test/sandbox gateway domain isapi-qa.rizzitbuy.com. Replace placeholders such as{tenant-id},{clientId},{clientSecret}with the actual values issued by operations.
5. Obtaining an Access Token
- Method & path:
POST /open-api/system/oauth2/token - Authentication: HTTP Basic. Base64-encode
clientId:clientSecretand put it in theAuthorizationheader (i.e.Authorization: Basic base64(clientId:clientSecret)). - Content-Type:
application/x-www-form-urlencoded
Request parameters:
| Parameter | Location | Required | Description |
|---|---|---|---|
Authorization |
Header | Yes | Basic base64(clientId:clientSecret) |
tenant-id |
Header | Yes | Tenant ID |
grant_type |
Body | Yes | Fixed value client_credentials |
scope |
Body | No | Space-separated; if omitted, all scopes granted to the application are used |
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/system/oauth2/token' \
-H 'Authorization: Basic {base64(clientId:clientSecret)}' \
-H 'tenant-id: {tenant-id}' \
-d 'grant_type=client_credentials' \
-d 'scope=goods:detail:read'
Response fields:
| Field | Type | Description |
|---|---|---|
access_token |
string | Access token, carried in subsequent business requests |
refresh_token |
string | Empty string in client-credentials mode (no refresh token; re-fetch after expiry) |
token_type |
string | Fixed value Bearer |
expires_in |
number | Token lifetime in seconds, e.g. 1800 |
scope |
string | The actually granted scopes, space-separated |
Response example:
{
"code": 0,
"data": {
"access_token": "xxxxxxxx",
"refresh_token": "",
"token_type": "Bearer",
"expires_in": 1800,
"scope": "goods:detail:read"
},
"msg": ""
}
Note: the open platform only supports
client_credentials. Passing any othergrant_type(such asauthorization_code/password/refresh_token) returns400with the message "the open platform only supports the client_credentials grant". The token'suserTypeis fixed toOPEN_APIand cannot access/admin-apior/app-api.
6. Calling Business Endpoints
Every business request must include:
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer {access_token} |
tenant-id |
Yes | The tenant ID, matching the one used to obtain the token |
Content-Type |
Yes (when there is a body) | application/json |
7. API Reference
7.1 Query Goods Detail (pilot)
- Method & path:
POST /open-api/goods/detail - Required scope:
goods:detail:read
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
goodsId |
string | Yes | Goods ID; must not be empty and must not be 0 |
source |
integer | Yes | Goods source: 1=Taobao, 2=1688, 3=Weidian |
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/goods/detail' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"goodsId":"123456","source":1}'
Response fields:
| Field | Type | Description |
|---|---|---|
goodsId |
string | Goods ID |
goodsTitle |
string | Goods title |
goodsDetailUrl |
string | Goods detail page URL |
goodsPicUrl |
string | Goods main image |
price |
string | Price (in yuan) |
priceInCents |
number | Price (in cents) |
orginalPrice |
string | Original price (in yuan) |
stockNum |
string | Stock quantity |
salesCount |
string | Sales count |
goodsImageUrlList |
string[] | List of goods image URLs |
postFee |
string | Shipping fee (in yuan) |
goodsSource |
integer | Goods source: 1=Taobao, 2=1688, 3=Weidian |
skuList |
object[] | SKU list; element fields below |
skuSpecInfoList |
object[] | SKU spec dimensions (e.g. color, size) for selecting a SKU; element fields below |
skuList element fields:
| Field | Type | Description |
|---|---|---|
skuId |
string | SKU ID |
specId |
string | 1688 spec ID |
price |
string | SKU price (yuan) |
priceInCents |
number | SKU price (cents) |
salePrice |
string | SKU sale price (yuan) |
salePriceInCents |
number | SKU sale price (cents) |
quantity |
integer | SKU stock quantity |
imageUrl |
string | SKU image URL |
propertiesId |
string | SKU properties ID |
propertiesName |
string | SKU properties name |
skuSpecInfoList element fields:
| Field | Type | Description |
|---|---|---|
skuSpecName |
string | Spec dimension name, e.g. color, size |
skuSpecList |
object[] | Values in this dimension: pid, vid, pname, vname, icon |
Response example:
{
"code": 0,
"data": {
"goodsId": "123456",
"goodsTitle": "Sample Goods",
"goodsDetailUrl": "https://example.com/item/123456",
"goodsPicUrl": "https://example.com/img/123456.jpg",
"price": "99.00",
"priceInCents": 9900,
"orginalPrice": "129.00",
"stockNum": "1000",
"salesCount": "532",
"goodsImageUrlList": [
"https://example.com/img/1.jpg",
"https://example.com/img/2.jpg"
],
"postFee": "0.00",
"goodsSource": 1,
"skuList": [
{
"skuId": "5001",
"specId": null,
"price": "99.00",
"priceInCents": 9900,
"salePrice": "99.00",
"salePriceInCents": 9900,
"quantity": 100,
"imageUrl": "https://example.com/img/sku-5001.jpg",
"propertiesId": "1627207:28341",
"propertiesName": "颜色:红色;尺码:M"
}
],
"skuSpecInfoList": [
{
"skuSpecName": "颜色",
"skuSpecList": [
{ "pid": "1627207", "vid": "28341", "pname": "颜色", "vname": "红色", "icon": null }
]
}
]
},
"msg": ""
}
7.2 Query Goods QC Detail
- Method & path:
POST /open-api/goods/qc-detail - Required scope:
goods:qc:read
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
goodsId |
string | Yes | Goods ID; must not be empty and must not be 0 |
source |
integer | Yes | Goods source: 1=Taobao, 2=1688, 3=Weidian |
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/goods/qc-detail' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"goodsId":"123456","source":1}'
Response fields:
| Field | Type | Description |
|---|---|---|
goodsId |
string | Goods ID |
qcPathList |
string[] | QC photo URL list |
length |
string | Length (cm) |
width |
string | Width (cm) |
height |
string | Height (cm) |
weight |
string | Weight (g) |
volume |
string | Volume (cm3) |
completionTime |
string | QC completion time (yyyy-MM-dd HH:mm:ss) |
Note: for internal information protection, the QC endpoints do not return inspector / photographer staff IDs or names.
Response example:
{
"code": 0,
"data": {
"goodsId": "123456",
"qcPathList": [
"https://example.com/qc/1.jpg",
"https://example.com/qc/2.jpg"
],
"length": "30",
"width": "20",
"height": "10",
"weight": "500",
"volume": "6000",
"completionTime": "2026-06-02 18:30:00"
},
"msg": ""
}
7.3 Query Goods QC Image List
- Method & path:
POST /open-api/goods/qc-images - Required scope:
goods:qc:read - Request body: same as 7.2 (
goodsId+source)
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/goods/qc-images' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"goodsId":"123456","source":1}'
Response example: data is an array of QC image URLs.
{
"code": 0,
"data": [
"https://example.com/qc/1.jpg",
"https://example.com/qc/2.jpg"
],
"msg": ""
}
7.4 Paginated QC Data Query by Time
- Method & path:
POST /open-api/goods/qc-page - Required scope:
goods:qc:read
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
pageNo |
integer | Yes | Page number, starting from 1 |
pageSize |
integer | Yes | Page size |
goodsId |
string | No | Filter by exact goods ID |
source |
integer | No | Goods source: 1=Taobao, 2=1688, 3=Weidian |
createTime |
string[] | No | Record creation time range [start, end], format yyyy-MM-dd HH:mm:ss |
completionTime |
string[] | No | QC completion time range [start, end], format yyyy-MM-dd HH:mm:ss |
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/goods/qc-page' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{
"pageNo": 1,
"pageSize": 10,
"completionTime": ["2026-06-01 00:00:00", "2026-06-02 23:59:59"]
}'
Response fields: data.list is an array of QC details (same fields as 7.2), data.total is the total count.
{
"code": 0,
"data": {
"list": [
{
"goodsId": "123456",
"qcPathList": ["https://example.com/qc/1.jpg"],
"length": "30",
"width": "20",
"height": "10",
"weight": "500",
"volume": "6000",
"completionTime": "2026-06-02 18:30:00"
}
],
"total": 1
},
"msg": ""
}
7.5 Search Goods by Image
- Method & path:
POST /open-api/goods/search-by-images - Required scope:
goods:search:read
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
imagesUrl |
string | Yes | Image URL; must be a publicly accessible image address (common image extensions such as .jpg/.png). An invalid format returns "The image URL format is invalid" |
page |
integer | Yes | Current page, starting from 1 |
source |
integer | Yes | Goods source: 1=Taobao, 2=1688, 3=Weidian |
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/goods/search-by-images' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"imagesUrl":"https://example.com/img/query.jpg","page":1,"source":1}'
Response fields:
| Field | Type | Description |
|---|---|---|
goodsList |
object[] | Goods list; element fields below |
page |
integer | Current page |
size |
integer | Page size |
totalPage |
integer | Total pages |
totalCount |
integer | Total count |
goodsList element fields:
| Field | Type | Description |
|---|---|---|
goodsId |
string | Goods ID |
goodsTitle |
string | Goods title |
goodsDetailUrl |
string | Goods detail page URL |
goodsPicUrl |
string | Goods main image |
goodsSource |
integer | Goods source: 1=Taobao, 2=1688, 3=Weidian |
price |
string | Price (yuan) |
priceInCents |
number | Price (cents) |
originPriceInCents |
number | Original/strike-through price (cents) |
salesCount |
string | Sales count |
hasDiscount |
boolean | Whether a promotion applies |
discountPriceInCents |
number | Discounted price (cents) |
Note: to protect internal information, the open API does not return member-scoped fields such as collection status or personalized share links.
Response example:
{
"code": 0,
"data": {
"goodsList": [
{
"goodsId": "123456",
"goodsTitle": "Sample Goods",
"goodsDetailUrl": "https://example.com/item/123456",
"goodsPicUrl": "https://example.com/img/123456.jpg",
"goodsSource": 1,
"price": "99.00",
"priceInCents": 9900,
"originPriceInCents": 9900,
"salesCount": "532",
"hasDiscount": true,
"discountPriceInCents": 8900
}
],
"page": 1,
"size": 20,
"totalPage": 5,
"totalCount": 100
},
"msg": ""
}
7.6 Parse Goods URL
- Method & path:
POST /open-api/goods/search-url-parse - Required scope:
goods:search:read - Description: Parses short or long links from Taobao/Tmall, 1688, Weidian, and common agent sites (cssbuy, cnfans, hoobuy, etc.) to extract the platform goods ID and source. Unrecognized links return "Failed to parse product URL".
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
searchUrl |
string | Yes | The goods link to parse. Supports short links, long links, and pasted text with noise (spaces and Chinese characters are stripped automatically). |
rno |
string | No | Promotion code; when non-empty it is appended to the response targetGoodsDetailUrl. |
Request example:
curl -X POST 'https://api.rizzitgo.com/open-api/goods/search-url-parse' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant id}' \
-H 'Content-Type: application/json' \
-d '{"searchUrl":"https://detail.tmall.com/item.htm?id=768650559131","rno":"ABC123"}'
Response fields:
| Field | Type | Description |
|---|---|---|
goodsId |
string | Platform goods ID |
goodsSource |
integer | Goods source: 1=Taobao, 2=1688, 3=Weidian, 4=Other |
goodsSourceName |
string | Goods source name (taobao/alibaba/weidian) |
goodsDetailUrl |
string | Original platform goods detail page URL |
targetGoodsDetailUrl |
string | In-site share link (includes the promotion code when rno is non-empty) |
success |
boolean | Whether parsing succeeded |
searchUrl |
string | The cleaned input link |
Response example:
{
"code": 0,
"data": {
"goodsId": "768650559131",
"goodsSource": 1,
"goodsSourceName": "taobao",
"goodsDetailUrl": "https://detail.tmall.com/item.htm?id=768650559131",
"targetGoodsDetailUrl": "https://www.rizzitgo.com/detailPage?goodsId=768650559131&source=1&rno=ABC123",
"success": true,
"searchUrl": "https://detail.tmall.com/item.htm?id=768650559131"
},
"msg": ""
}
7.7 Redeem Coupon by Code (issue by email or Discord user ID)
- Method & path:
POST /open-api/promotion/redeem-code/redeem - Required scope:
promotion:redeem-code:redeem - Description: Uses a pre-configured redeem code from the platform admin (which can bind N coupon templates and randomly hit one by weight) to issue a coupon to a member. Identify the member with either
emailordiscordUserId(at least one required). When both are sent, Discord is used and email is not a fallback. The member must already exist (exact email match, or a Discord account already bound to a member); otherwise it returns "Member does not exist". This endpoint does not auto-create members.
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | Yes | Redeem code |
email |
string | Either this or discordUserId |
Email of the recipient member, must exactly match a platform member account |
discordUserId |
string | Either this or email |
Discord user ID (snowflake, stored as social openid) |
requestId |
string | No | External request id for idempotency; the same requestId is processed only once within 10 minutes, duplicates return "Duplicate request, please do not retry" |
Request example (by email):
curl -X POST 'https://api.rizzitgo.com/open-api/promotion/redeem-code/redeem' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenantId}' \
-H 'Content-Type: application/json' \
-d '{"code":"E602F4DC626E4948","email":"[email protected]","requestId":"REQ-20260604-0001"}'
Request example (by Discord user ID):
curl -X POST 'https://api.rizzitgo.com/open-api/promotion/redeem-code/redeem' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenantId}' \
-H 'Content-Type: application/json' \
-d '{"code":"E602F4DC626E4948","discordUserId":"123456789012345678","requestId":"REQ-20260824-0001"}'
Response fields:
| Field | Type | Description |
|---|---|---|
code |
string | Redeem code |
email |
string | Recipient member email; filled from the member when issuing by Discord (may be null) |
discordUserId |
string | Discord user ID; echoed when issuing by Discord, null when issuing by email |
prize |
string | Prize description, auto-generated from the coupon discount: percentage coupon as 30% OFF, amount coupon as $10 OFF (USD, converted from cents); comma-separated when multiple; falls back to coupon title when no discount info |
success |
boolean | Whether redemption succeeded |
message |
string | Result description |
coupons |
object[] | Coupons issued in this redemption (usually 1 in random mode); element fields below |
coupons element fields:
| Field | Type | Description |
|---|---|---|
templateId |
number | Coupon template ID |
title |
string | Coupon title |
couponType |
integer | Coupon type: 1=shipping, 2=product, 3=site-wide |
discountType |
integer | Discount type: 1=amount-off, 2=percentage-off |
discountPrice |
number | Discount amount (in cents) |
discountPercent |
number | Discount percent (effective when discountType=2, e.g. 80 means 20% off) |
usePriceCondition |
number | Threshold: minimum spend to use (in cents, 0 = no threshold) |
validStartTime |
string | Valid from |
validEndTime |
string | Valid until |
Response example:
{
"code": 0,
"data": {
"code": "E602F4DC626E4948",
"email": "[email protected]",
"discordUserId": null,
"prize": "30% OFF",
"success": true,
"message": "兑换成功,共获得 1 张优惠券",
"coupons": [
{
"templateId": 1001,
"title": "满100减10",
"couponType": 2,
"discountType": 1,
"discountPrice": 1000,
"discountPercent": null,
"usePriceCondition": 10000,
"validStartTime": "2026-06-01 00:00:00",
"validEndTime": "2026-06-30 23:59:59"
}
]
},
"msg": ""
}
Business errors: omitting both
discordUserIdreturns "Please provide email or Discord user ID"; no member found by email or Discord (including unbound Discord or deleted member) returns "Member does not exist"; non-existent/expired/voided redeem codes and per-user or per-day (incl. per-IP) redemption limits reuse the existing redeem-code error codes. Redemption limits, validity and quotas are configured in the admin; please call within the agreed quota.
7.8 Member coupon query / extend / restore
Locate a member by email, member number (unionId), or user ID; query their coupons; extend unused coupons or restore expired ones. All three endpoints use the same user identifier rule: provide exactly one of the three fields, with priority userId > unionId > email.
Coupon status codes (string in both request and response, not numeric):
| Code | Meaning |
|---|---|
UNUSED |
Not used |
USED |
Used |
FINISH |
Redeemed/settled |
EXPIRE |
Expired |
INVALID |
Voided |
7.8.1 Paginated member coupon query
- Method & path:
POST /open-api/promotion/member-coupon/page - Required scope:
promotion:member-coupon:read
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
pageNo |
integer | No | Page number, starts at 1 (default 1) |
pageSize |
integer | No | Page size (default 10) |
email |
string | One of three | Member email |
unionId |
string | One of three | Member number |
userId |
number | One of three | User ID |
status |
string | No | Exact status filter, e.g. EXPIRE for expired coupons |
code |
string | No | Coupon code (fuzzy match) |
templateId |
number | No | Coupon template ID |
Response data: list (coupon items), total (count). Each item includes id, templateId, title, code, status (string code), discount fields, validStartTime, validEndTime, useTime, takeTime.
Example:
curl -X POST 'https://api.rizzitgo.com/open-api/promotion/member-coupon/page' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","status":"EXPIRE","pageNo":1,"pageSize":10}'
7.8.2 Extend unused coupons
- Method & path:
POST /open-api/promotion/member-coupon/extend - Required scope:
promotion:member-coupon:extend - Note: Only coupons with
status=UNUSEDcan be extended.
| Field | Type | Required | Description |
|---|---|---|---|
email / unionId / userId |
— | One of three | Locate member |
couponIds |
number[] | Yes | Coupon ID list |
extendDays |
integer | Yes | Extension days, 1–365 |
Response data: successCount, coupons (id, status, validEndTime).
7.8.3 Restore expired coupons
- Method & path:
POST /open-api/promotion/member-coupon/restore - Required scope:
promotion:member-coupon:restore - Note: Only coupons with
status=EXPIREcan be restored toUNUSEDwith a new validity period (default 15 days, configurable in admin).
| Field | Type | Required | Description |
|---|---|---|---|
email / unionId / userId |
— | One of three | Locate member |
couponIds |
number[] | Yes | Coupon ID list |
Response data: successCount, coupons (id, status=UNUSED, validEndTime).
Business errors:
1_013_024_000missing user identifier;1_013_024_001member not found;1_013_024_002coupon not owned by user;1_013_024_003invalid status code;1_013_024_004restore when notEXPIRE; extend when notUNUSEDreturns1_013_003_005.
7.9 Promoter spreadsheet product pagination
Page a promoter's spreadsheet (shared product list) by referral code rno. Optional filters: custom category, keyword, product source, price range, and sort order.
- Method & path:
POST /open-api/promotion/spreadsheet/page - Required scope:
promotion:spreadsheet:read
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
pageNo |
integer | No | Page number, starting from 1 (default 1) |
pageSize |
integer | No | Page size (default 10) |
rno |
string | Yes | Promoter referral code |
categoryCode |
string | No | Promoter custom category code; omit to list all categories |
keyword |
string | No | Search keyword (product title) |
source |
integer | No | Product source: 1=Taobao, 2=1688, 3=Weidian |
sort |
integer | No | Sort: omit=created time desc; 1=sales desc; 2=price asc; 3=price desc |
minGoodsPrice |
number | No | Minimum price in CNY cents |
maxGoodsPrice |
number | No | Maximum price in CNY cents |
Response data:
| Field | Type | Description |
|---|---|---|
list |
object[] | Product list (see fields below) |
total |
number | Total count |
Main fields in each list item: goodsId, goodsTitle, localGoodsTitle, priceInCents, priceInUsd (USD amount from CNY cents using DB exchange rate), goodsSource, goodsPicUrl, goodsImageUrlList (full image list when async-synced; otherwise may contain only the main image), goodsDetailUrl (includes rno), goodsSaleCount, goodsSda, goodsCategoryCode, qcInfoList (latest up to 5 QC groups; empty array when none; element fields match open goods QC: goodsId, skuId, source, goodsName, localGoodsName, specName, localSpecName, imagePath, goodsDetailUrl, qcPathList, length, width, height, weight, volume, completionTime; no inspector/photographer fields).
Example:
curl -X POST 'https://api.rizzitgo.com/open-api/promotion/spreadsheet/page' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"rno":"ABC123","categoryCode":"cat_001","pageNo":1,"pageSize":10}'
Business errors:
1_013_025_000missing rno;1_013_007_000promoter not found (invalid rno).
8. Revoking a Token (optional)
- Method & path:
POST /open-api/system/oauth2/token/revoke - Authentication: same as obtaining a token (HTTP Basic)
- Parameter:
token={access_token}(application/x-www-form-urlencoded)
curl -X POST 'https://api.rizzitgo.com/open-api/system/oauth2/token/revoke' \
-H 'Authorization: Basic {base64(clientId:clientSecret)}' \
-H 'tenant-id: {tenant-id}' \
-d 'token={access_token}'
9. Unified Response Structure and Error Codes
All endpoints return the unified structure { code, data, msg }: code = 0 means success, anything else means failure, and msg carries the message.
Common errors:
| HTTP / code | Meaning | Suggested handling |
|---|---|---|
401 |
Token missing / invalid / expired | Obtain a new token and retry |
403 |
Insufficient scope / wrong user type | Contact operations to grant the required scope |
429 |
Rate limited (per clientId) |
Lower the call rate, retry with exponential backoff, request a higher QPS if needed |
400 |
Invalid parameter / unsupported grant_type | Check request parameters and grant type |
10. Security and Limits
- IP whitelist: if operations configured
ipWhitelistfor the application (comma-separated, multiple IPs), only source IPs in the whitelist may call; empty means no restriction. - Rate limiting: a per-application QPS can be configured (
rateLimitQps,0means unlimited). Exceeding it returns429. - Secret storage:
clientSecretis shown only once; never embed it in frontend/client code, logs, or version control. If leaked, immediately contact operations to "Reset Secret" under "Partner Applications"; the old secret is invalidated instantly. - Token caching and concurrent refresh: cache the
access_tokenon the client and reuse it withinexpires_into avoid frequent token fetches. Refresh ahead of expiry with a buffer (e.g. when less than 60s remain), and lock the refresh to prevent concurrent duplicate fetches. - Retry and backoff: on
401, re-fetch the token and retry once; on429or network jitter, retry with exponential backoff (e.g. 1s, 2s, 4s) with an upper bound. - Multi-tenancy: always carry a
tenant-idconsistent with the token to avoid cross-tenant access being rejected.
11. Code Samples (obtain token -> query goods detail)
cURL
# 1) obtain token
TOKEN=$(curl -s -X POST 'https://api.rizzitgo.com/open-api/system/oauth2/token' \
-H 'Authorization: Basic {base64(clientId:clientSecret)}' \
-H 'tenant-id: {tenant-id}' \
-d 'grant_type=client_credentials' \
-d 'scope=goods:detail:read' | jq -r '.data.access_token')
# 2) query goods detail
curl -X POST 'https://api.rizzitgo.com/open-api/goods/detail' \
-H "Authorization: Bearer ${TOKEN}" \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"goodsId":"123456","source":1}'
Java (JDK 11+ HttpClient)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;
public class OpenApiDemo {
static final String GATEWAY = "https://api.rizzitgo.com";
static final String TENANT_ID = "{tenant-id}";
static final String CLIENT_ID = "{clientId}";
static final String CLIENT_SECRET = "{clientSecret}";
public static void main(String[] args) throws Exception {
HttpClient http = HttpClient.newHttpClient();
// 1) obtain token
String basic = Base64.getEncoder()
.encodeToString((CLIENT_ID + ":" + CLIENT_SECRET).getBytes());
HttpRequest tokenReq = HttpRequest.newBuilder()
.uri(URI.create(GATEWAY + "/open-api/system/oauth2/token"))
.header("Authorization", "Basic " + basic)
.header("tenant-id", TENANT_ID)
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(
"grant_type=client_credentials&scope=goods:detail:read"))
.build();
HttpResponse<String> tokenResp = http.send(tokenReq, HttpResponse.BodyHandlers.ofString());
System.out.println(tokenResp.body());
// In a real project, parse data.access_token with a JSON library
String accessToken = "<parse data.access_token from tokenResp>";
// 2) query goods detail
HttpRequest bizReq = HttpRequest.newBuilder()
.uri(URI.create(GATEWAY + "/open-api/goods/detail"))
.header("Authorization", "Bearer " + accessToken)
.header("tenant-id", TENANT_ID)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"goodsId\":\"123456\",\"source\":1}"))
.build();
HttpResponse<String> bizResp = http.send(bizReq, HttpResponse.BodyHandlers.ofString());
System.out.println(bizResp.body());
}
}
Python (requests)
import base64
import requests
GATEWAY = "https://api.rizzitgo.com"
TENANT_ID = "{tenant-id}"
CLIENT_ID = "{clientId}"
CLIENT_SECRET = "{clientSecret}"
# 1) obtain token
basic = base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode()
token_resp = requests.post(
f"{GATEWAY}/open-api/system/oauth2/token",
headers={"Authorization": f"Basic {basic}", "tenant-id": TENANT_ID},
data={"grant_type": "client_credentials", "scope": "goods:detail:read"},
)
access_token = token_resp.json()["data"]["access_token"]
# 2) query goods detail
biz_resp = requests.post(
f"{GATEWAY}/open-api/goods/detail",
headers={
"Authorization": f"Bearer {access_token}",
"tenant-id": TENANT_ID,
"Content-Type": "application/json",
},
json={"goodsId": "123456", "source": 1},
)
print(biz_resp.json())
11.1 System exchange rate list — POST /open-api/pay/exchange-rate/list
- Required scope:
pay:exchange-rate:read - operationId:
PayExchangeAPI - Request: no body (an empty JSON
{}is accepted)
Returns the configured system exchange rate for every enabled currency. The base currency is CNY: 1 CNY = exchangeRate of that currency. This endpoint does not return the real-time rate and does not apply country/customer premium policies.
Conversion: amount_foreign = amount_CNY × exchangeRate (e.g. CNY 100 with USD exchangeRate = 0.14 → USD 14).
curl -X POST 'https://api.rizzitgo.com/open-api/pay/exchange-rate/list' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{}'
Response data item fields: name, abbreviationCode (ISO code such as USD / EUR / CNY), symbol, exchangeRate (system rate vs CNY).
{
"code": 0,
"data": [
{
"name": "Chinese Yuan",
"abbreviationCode": "CNY",
"symbol": "¥",
"exchangeRate": 1
},
{
"name": "US Dollar",
"abbreviationCode": "USD",
"symbol": "$",
"exchangeRate": 0.140000
}
]
}
12. Purchase order and wallet pay
Scopes:
system:partner-member:read,order:purchase:quote,order:purchase:create,order:purchase:query,order:purchase:supplement-pay,pay:wallet:query,pay:wallet:pay
Place a purchase order on behalf of a bound member and debit their wallet. Amount fields are CNY cents. Server-side live prices are used; client-supplied prices are ignored.
Prerequisite: operations binds the partner externalUserId to a platform member under Admin Console "Open Platform / Member Bind". Binding enables repayment auth by default so buyer-agent supplements can auto-debit.
Recommended sequence:
POST /open-api/system/oauth2/tokenPOST /open-api/system/partner-member/query(optional bind check)POST /open-api/order/purchase/quotePOST /open-api/order/purchase/create(idempotent onoutOrderNo)POST /open-api/pay/wallet/pay(usepaymentIdfrom step 4)
Supplement is not part of the happy path. Auto-debit runs when auth is on and balance is enough. Only then: supplement/list → supplement/trade-no → wallet/pay.
platformChannel: 1 Taobao, 2 1688, 3 Weidian, 5 Xianyu.
12.1 Query member bind — POST /open-api/system/partner-member/query
- Required scope:
system:partner-member:read - operationId:
QueryMemberBindAPI
Unbound or disabled bindings return a business error.
Request: { "externalUserId": "shopify_10086" }
Response data: externalUserId, memberUnionId (member code for human check), bound.
curl -X POST 'https://api.rizzitgo.com/open-api/system/partner-member/query' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"externalUserId":"shopify_10086"}'
12.1.1 List member binds — POST /open-api/system/partner-member/list
- Required scope:
system:partner-member:read(same as single-bind query) - operationId:
QueryMemberBindListAPI
No request body. Identifies the partner from the access token and returns all binds (including disabled) plus each member's wallet balance. Empty array when none exist. Numeric member id is not exposed. Wallet lookup failures return 0 balance without failing the list.
Response data[]: externalUserId, memberUnionId, status (0=enabled, 1=disabled), balance (available, fen), freezePrice (frozen, fen), currencyCode (CNY).
curl -X POST 'https://api.rizzitgo.com/open-api/system/partner-member/list' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json'
12.2 Quote — POST /open-api/order/purchase/quote
- Required scope:
order:purchase:quote - operationId:
PurchaseQuoteAPI
Does not create an order. Use returned payAmount as expectedPayAmount on create.
Request: externalUserId (required), items[] with platformChannel, goodsId, skuId, qty (1–9999), optional remarks.
Response data: goodsTotalAmount, freightTotalAmount, payAmount, currencyCode (CNY), shops[].
curl -X POST 'https://api.rizzitgo.com/open-api/order/purchase/quote' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"externalUserId":"shopify_10086","items":[{"platformChannel":1,"goodsId":"654321","skuId":"5001","qty":2}]}'
12.3 Create purchase order — POST /open-api/order/purchase/create
- Required scope:
order:purchase:create - operationId:
PurchaseCreateAPI
outOrderNo is idempotent per partner. A successful prior create is replayed with duplicated=true.
Request: required outOrderNo, externalUserId, items; optional addressId (default member address if omitted), orderComment, expectedPayAmount (reject if live price deviation exceeds the threshold).
Response data: outOrderNo, orderNo, paymentId, payAmount, expireTime, duplicated.
curl -X POST 'https://api.rizzitgo.com/open-api/order/purchase/create' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"outOrderNo":"SHOPIFY-20260811-0001","externalUserId":"shopify_10086","expectedPayAmount":24600,"items":[{"platformChannel":1,"goodsId":"654321","skuId":"5001","qty":2}]}'
12.4 Query purchase order — POST /open-api/order/purchase/query
- Required scope:
order:purchase:query - operationId:
PurchaseQueryAPI
Pass either outOrderNo or orderNo. Only orders created by this partner are returned.
Response data: paymentId, payAmount, refStatus (0 processing / 1 created / 2 failed), orders[] (split by shop).
12.5 Query wallet balance — POST /open-api/pay/wallet/balance
- Required scope:
pay:wallet:query - operationId:
WalletBalanceAPI
Request: { "externalUserId": "shopify_10086" }
Response data: balance (available, cents), freezePrice, currencyCode (CNY).
12.6 Wallet pay — POST /open-api/pay/wallet/pay
- Required scope:
pay:wallet:pay - operationId:
WalletPayAPI
The business order is checked before debiting. Already-paid paymentId is rejected; query instead.
Request: required externalUserId (same as create), paymentId; optional payAmount (must match the pay order).
Response data: status (0 unpaid / 10 success / 20 refunded / 30 closed), paySuccess, payAmount, successTime, balance (remaining after debit).
curl -X POST 'https://api.rizzitgo.com/open-api/pay/wallet/pay' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"externalUserId":"shopify_10086","paymentId":"P2026081100001","payAmount":24600}'
12.7 List supplements — POST /open-api/order/purchase/supplement/list
- Required scope:
order:purchase:query - operationId:
PurchaseSupplementListAPI
Needed only when auto-debit failed.
Request: { "externalUserId": "shopify_10086" }
Response data: supplementTotalAmount, orders[]. bizType: 1 purchase, 2 bag. expenseType: 102 goods, 104 freight, 203 bag freight. Use orderExpensesNo in the next call.
12.8 Create supplement pay order — POST /open-api/order/purchase/supplement/trade-no
- Required scope:
order:purchase:supplement-pay - operationId:
PurchaseSupplementTradeNoAPI
Do not mix purchase and bag expense nos in one request. Then call wallet/pay with paymentId.
Request: { "externalUserId": "shopify_10086", "orderExpensesNoList": ["OE2026081100001"] }
Response data: paymentId, payAmount, payType (3 freight / 6 goods / 7 bag / 8 goods+freight).
13. Order and bag-order APIs
Scopes:
order:bag-order:read,order:order-item:read
List endpoints require a member: pass at least one of memberId or unionId. Amount fields (price / actualPrice / freightFee / goodsTotalAmount) are in CNY cents.
13.1 Query bag order by number — POST /open-api/order/bag-order/query
- Required scope:
order:bag-order:read
Request: { "bagOrderNo": "BG20250624001" }
Response data: exists, bagOrderNo, status, statusDesc, createTime, unionId.
Bag status: 0 unpaid, 1 pending review, 2 pending outbound, 3 outbound in progress, 4 pending extra payment, 5 pending shipment, 6 shipped, 7 received, 8 returned, 9 cancelled, 10 closed.
curl -X POST 'https://api.rizzitgo.com/open-api/order/bag-order/query' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"bagOrderNo":"BG20250624001"}'
13.2 Page bag orders — POST /open-api/order/bag-order/page
- Required scope:
order:bag-order:read
Required: pageNo, pageSize, and at least one of memberId / unionId. Optional filters: status, bagOrderNo, createTime ([start, end], yyyy-MM-dd HH:mm:ss).
List item fields: bagOrderNo, outboundOrderNo, status, statusDesc, goodsQty, goodsTotalAmount (cents), estimateWeight, estimateVolume, unionId, createTime.
curl -X POST 'https://api.rizzitgo.com/open-api/order/bag-order/page' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"unionId":"M123456","pageNo":1,"pageSize":10}'
13.3 Page order items — POST /open-api/order/order-item/page
- Required scope:
order:order-item:read
Required: pageNo, pageSize, and at least one of memberId / unionId. Optional: status, orderNo, orderItemNo, createTime.
List item fields: orderNo, orderItemNo, status, unionId, goodsName, localGoodsName, specName, localSpecName, imagePath, qty, price, actualPrice, freightFee, shopName, localShopName, createTime.
Common item status values: 101 unpaid, 105 cancelled, 201 pending accept, 204 purchasing, 206 merchant shipped, 305 warehoused, 308 shipped.
curl -X POST 'https://api.rizzitgo.com/open-api/order/order-item/page' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"unionId":"M123456","pageNo":1,"pageSize":10}'
14. Logistics tracking
- Method & path:
POST /open-api/logistics/track/query - Required scope:
logistics:track:query
Unified entry for domestic (type=1) and international (type=2) tracking. For domestic queries, carrierName improves recognition. For international queries, language (zh / en / es) controls translation.
| Field | Required | Description |
|---|---|---|
trackingNo |
Yes | Carrier number / international tracking number |
type |
Yes | 1=domestic, 2=international |
carrierName |
No | Carrier name (domestic, optional) |
language |
No | Language preference for international tracks |
Common response fields: trackingNo, type, status, trackContent, trackDate, trackItems (currentPosition, content, trackDate, status).
Track status: PENDING, IN_TRANSIT, DELIVERING, DELIVERED, EXCEPTION.
Domestic extras: carrierName, carrierCode, checkStatus, arrivalTime.
International extras: logisticsOrderNo, expressNo, lastMileTrackingNo, supplierCode, supplierName, logisticsLineName, trackUrl, shipCountry, country.
curl -X POST 'https://api.rizzitgo.com/open-api/logistics/track/query' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"trackingNo":"YT9876543210","type":1,"carrierName":"YTO"}'
14.1 Freight estimate — POST /open-api/logistics/line/freight-estimate
- Required scope:
logistics:freight-estimate:read - operationId:
FreightEstimateAPI
Estimates freight for available lines by destination country and weight. Only available lines are returned. totalFee is the system freight in CNY cents (C-end promotions are not applied). This version accepts country and weight only (no dimensions, province, or mail-restriction type). When language is omitted, lineName is English; when it is set, lineName is Google-translated.
Request:
| Field | Required | Description |
|---|---|---|
countryCode |
Yes | Destination country code, e.g. US |
weight |
Yes | Parcel weight in grams |
language |
No | Target language for lineName, e.g. en / zh / es. Defaults to en. When set, lineName is Google-translated. |
Response data item fields:
| Field | Description |
|---|---|
id |
Line ID |
lineUUid |
Line UUID |
lineName |
Line name (translated when language is set) |
icon |
Line icon URL |
referenceTime |
Estimated transit time |
totalFee |
System freight in CNY cents |
billingType |
Billing type: 1 actual weight, 2 volumetric weight |
curl -X POST 'https://api.rizzitgo.com/open-api/logistics/line/freight-estimate' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"countryCode":"US","weight":1000}'
Response example:
{
"code": 0,
"data": [
{
"id": 7785,
"lineUUid": "a1b2c3d4",
"lineName": "US-EMS",
"icon": "https://cdn.rizzitgoo.com/line/ems.png",
"referenceTime": "7-12 days",
"totalFee": 8800,
"billingType": 1
}
]
}
15. Discord authorize URL
- Method & path:
POST /open-api/member/auth/discord-authorize-url - Required scope:
member:auth:discord-login
Partners (e.g. a Discord bot) can obtain the platform Discord OAuth login URL. redirectUri must be an https:// URL and must exactly match a Redirect registered in the Discord Developer Portal.
Request: { "redirectUri": "https://rizzitgo.com" }
Response data: authorizeUrl.
curl -X POST 'https://api.rizzitgo.com/open-api/member/auth/discord-authorize-url' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"redirectUri":"https://rizzitgo.com"}'
15.1 Query Discord login status
- Method & path:
POST /open-api/member/auth/discord-login-status - Required scope:
member:auth:discord-login
Look up whether a Discord user ID (snowflake, stored as social openid) is bound to a member. Unauthenticated users still get HTTP 200 with loggedIn=false, so bots can poll. A bind whose member has been deleted is treated as not logged in.
Request: { "discordUserId": "123456789012345678" }
Response data:
| Field | Description |
|---|---|
loggedIn |
Whether Discord login is complete (bound to a member) |
memberId |
Member primary key; null when not logged in |
unionId |
Public member code; null when not logged in or the member was deleted |
curl -X POST 'https://api.rizzitgo.com/open-api/member/auth/discord-login-status' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"discordUserId":"123456789012345678"}'
16. Member consumption query
- Method & path:
POST /open-api/member/consumption/query - Required scope:
member:consumption:read - operationId:
MemberConsumptionAPI
Summarizes paid parcels and wallet recharges for a member. Amounts are in CNY cents. Omit createTime for lifetime totals. When provided, both start and end are required, and start must not be after end.
The time range is applied to parcel submit time (create_time) and recharge pay time (pay_time) respectively.
Member identifier (at least one): memberId, unionId, or discordOpenId (Discord snowflake, stored as social openid; same value as discordUserId on the login-status endpoint). When multiple identifiers are sent they must resolve to the same member, otherwise the API returns "User does not exist".
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
memberId |
number | One of three | Member primary key |
unionId |
string | One of three | Public member code |
discordOpenId |
string | One of three | Discord Open ID (snowflake) |
createTime |
string[] | No | Statistics range [start, end], format yyyy-MM-dd HH:mm:ss; omit for lifetime totals |
Response data fields:
| Field | Type | Description |
|---|---|---|
memberId |
number | Resolved member primary key |
unionId |
string | Public member code |
discordOpenId |
string | Echoed only when the request includes discordOpenId; otherwise null |
bagOrderCount |
number | Paid parcel order count (submitted and paid; excludes unpaid / cancelled / closed) |
bagConsumeAmount |
number | Net parcel consumption (actual paid minus refunds), CNY cents |
totalRechargeAmount |
number | Net wallet recharge credited (including bonus, minus refunds), CNY cents; mock / internal compensation / influencer channels are excluded |
rechargeCount |
number | Successful recharge count (same filter as net recharge) |
startTime |
string | Statistics start time; null for lifetime totals |
endTime |
string | Statistics end time; null for lifetime totals |
Lifetime totals by unionId:
curl -X POST 'https://api.rizzitgo.com/open-api/member/consumption/query' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{"unionId":"M123456"}'
By Discord Open ID with a time range:
curl -X POST 'https://api.rizzitgo.com/open-api/member/consumption/query' \
-H 'Authorization: Bearer {access_token}' \
-H 'tenant-id: {tenant-id}' \
-H 'Content-Type: application/json' \
-d '{
"discordOpenId":"123456789012345678",
"createTime":["2026-01-01 00:00:00","2026-09-03 23:59:59"]
}'
Response example:
{
"code": 0,
"data": {
"memberId": 1024,
"unionId": "M123456",
"discordOpenId": "123456789012345678",
"bagOrderCount": 12,
"bagConsumeAmount": 88000,
"totalRechargeAmount": 150000,
"rechargeCount": 5,
"startTime": "2026-01-01 00:00:00",
"endTime": "2026-09-03 23:59:59"
},
"msg": ""
}
Business errors: omitting every member identifier, or sending
createTimewithout both start and end (including start after end), fails request validation. Identifier lookup failure, unbound Discord, deleted member, or conflicting identifiers return1_004_001_000"User does not exist". Members with no parcels/recharges still succeed with counts of0.
17. FAQ
- Frequent
401s? Usually the token expired or was not cached. Reuse the token withinexpires_inand refresh before expiry; ensure theAuthorizationheader is in theBearer {access_token}format. - Consumption query returns "User does not exist"? Provide at least one of
memberId/unionId/discordOpenId. Lookup failure, unbound Discord, or identifiers that resolve to different members all return this error. - Getting
403? The application has not been granted thescoperequired by that endpoint. Contact operations to grant it. - Getting
429? You hit the per-clientIdQPS limit. Lower the rate and retry with backoff; request a higher quota if needed. - Cross-tenant access rejected? Ensure the
tenant-idheader matches the one used to obtain the token. clientSecretleaked? Immediately contact operations to "Reset Secret"; the old secret is invalidated instantly. Update the secret in your configuration.- Unbound external user? Operations must bind
externalUserIdto a member code under "Open Platform / Member Bind". Disabled binds cannot quote, create, or pay. - Create rejected for price deviation? The server uses live prices. Call
quotefirst and passpayAmountasexpectedPayAmountpromptly. - When to call supplement APIs? Auto-debit runs when repayment auth is on and balance is enough. Only if that fails:
supplement/list→supplement/trade-no→wallet/pay.
18. Online API Documentation
The gateway's Knife4j-aggregated Swagger includes an /open-api/** group, where you can view request/response definitions of each endpoint online to ease integration.
19. Document Version
| Version | Date | Changes |
|---|---|---|
| v2.8 | 2026-09 | Added member consumption query /open-api/member/consumption/query (scope member:consumption:read), look up paid parcel count, net parcel spend, and net wallet recharge by memberId / unionId / discordOpenId. |
| v2.7 | 2026-08 | Added partner-member bind list /open-api/system/partner-member/list (reuses scope system:partner-member:read), returning all binds of the current partner from the access token plus each member's wallet balance. |
| v2.6 | 2026-08 | Added purchase-order and wallet-pay flow: member-bind query, quote, create, query, wallet balance/pay, supplement list and supplement pay order; scopes system:partner-member:read, order:purchase:*, pay:wallet:*. |
| v2.5 | 2026-08 | Added freight estimate /open-api/logistics/line/freight-estimate (scope logistics:freight-estimate:read), returning available lines with id, lineUUid, name, transit time, system fee, and billing type. |
| v2.4 | 2026-08 | Added system exchange-rate list /open-api/pay/exchange-rate/list (scope pay:exchange-rate:read), returning configured rates vs CNY for enabled currencies. |
| v2.3 | 2026-08 | Goods detail /goods/detail now returns skuList and skuSpecInfoList. |
| v2.2 | 2026-08 | Redeem coupon /promotion/redeem-code/redeem can issue by Discord user ID: provide either email or discordUserId; Discord wins when both are sent. |
| v2.1 | 2026-08 | Added Discord login-status query /member/auth/discord-login-status (reuses scope member:auth:discord-login), look up whether a Discord user ID is bound to a member. |
| v2.0 | 2026-08 | Added bag-order pagination /order/bag-order/page, order-item page /order/order-item/page, logistics tracking /logistics/track/query, and Discord authorize URL /member/auth/discord-authorize-url, plus the corresponding scopes. |
| v1.0 | 2026-06 | Initial release: OAuth2 client-credentials integration, goods-detail pilot endpoint. |
| v1.1 | 2026-06 | Added goods QC endpoints: QC detail, QC image list, paginated QC query by time (scope goods:qc:read); token_type corrected to Bearer. |
| v1.2 | 2026-06 | Added search-goods-by-image endpoint /open-api/goods/search-by-images (scope goods:search:read). |
| v1.3 | 2026-06 | Added coupon redeem endpoint /open-api/promotion/redeem-code/redeem (scope promotion:redeem-code:redeem), issuing coupons to a member by email. |
| v1.4 | 2026-06 | Added goods URL parse endpoint /open-api/goods/search-url-parse (scope goods:search:read), with optional promotion code rno. |
| v1.5 | 2026-06 | Added member coupon query/extend/restore endpoints (scopes promotion:member-coupon:read/extend/restore); status uses string codes. |
| v1.9 | 2026-07 | Added promoter spreadsheet product pagination /open-api/promotion/spreadsheet/page (scope promotion:spreadsheet:read), query shared products by rno. |