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

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

  1. Contact platform operations and submit: partner name, contact (name / email / phone), source IPs for callbacks (optional, for the IP whitelist), and the required scopes.
  2. Operations creates the application under Admin Console "Open Platform / Partner Applications" and issues:
    • clientId
    • clientSecret (shown only once; store it securely)
    • the granted scope list (e.g. goods:detail:read)
    • tenant-id
  3. The partner exchanges clientId + clientSecret for an access_token, then calls business endpoints with the token.

Pre-launch checklist:


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-detail
POST /open-api/goods/qc-images
POST /open-api/goods/qc-page
3 goods:search:read Search goods POST /open-api/goods/search-by-images
POST /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/query
POST /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/query
POST /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-url
POST /open-api/member/auth/discord-login-status
19 system:partner-member:read Query partner-member bind POST /open-api/system/partner-member/query
POST /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/query
POST /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/token and /token/revoke) do not require any scope — they only need clientId + clientSecret authentication. 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 is api-qa.rizzitbuy.com. Replace placeholders such as {tenant-id}, {clientId}, {clientSecret} with the actual values issued by operations.


5. Obtaining an Access Token

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 other grant_type (such as authorization_code / password / refresh_token) returns 400 with the message "the open platform only supports the client_credentials grant". The token's userType is fixed to OPEN_API and cannot access /admin-api or /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)

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

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

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

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

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

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)

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 email and discordUserId returns "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

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

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

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_000 missing user identifier; 1_013_024_001 member not found; 1_013_024_002 coupon not owned by user; 1_013_024_003 invalid status code; 1_013_024_004 restore when not EXPIRE; extend when not UNUSED returns 1_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.

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_000 missing rno; 1_013_007_000 promoter not found (invalid rno).


8. Revoking a Token (optional)

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


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

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:

  1. POST /open-api/system/oauth2/token
  2. POST /open-api/system/partner-member/query (optional bind check)
  3. POST /open-api/order/purchase/quote
  4. POST /open-api/order/purchase/create (idempotent on outOrderNo)
  5. POST /open-api/pay/wallet/pay (use paymentId from step 4)

Supplement is not part of the happy path. Auto-debit runs when auth is on and balance is enough. Only then: supplement/listsupplement/trade-nowallet/pay.

platformChannel: 1 Taobao, 2 1688, 3 Weidian, 5 Xianyu.

12.1 Query member bind — POST /open-api/system/partner-member/query

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

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

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

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

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

Request: { "externalUserId": "shopify_10086" }

Response data: balance (available, cents), freezePrice, currencyCode (CNY).

12.6 Wallet pay — POST /open-api/pay/wallet/pay

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

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

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

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: 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: 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

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

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

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

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

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 createTime without both start and end (including start after end), fails request validation. Identifier lookup failure, unbound Discord, deleted member, or conflicting identifiers return 1_004_001_000 "User does not exist". Members with no parcels/recharges still succeed with counts of 0.


17. FAQ


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.