# 08. Webhook

# 1 Setting

# Webhook Configuration Requirements

# 1. Protocol Requirements
  • Supported Protocols: HTTPS
  • Encryption: TLS 1.2 or TLS 1.3 recommended for secure transmission
  • Request Method: POST
  • Content Type: Content-Type: application/json
# 2. Response Specifications
  • Success Status Code: 200 OK
  • Timeout: Response must be returned within 3 seconds
    (Avoid long-running or complex business logic to ensure prompt response)
  • URL Validation: The callback URL must be a public HTTPS address. Local addresses such as localhost and 127.0.0.1 are not supported.
  • Failure Message: If URL validation fails, the message field will return the concrete reason directly.

# 1.1 Message Setting(POST)

# URL

https://developers.cjdropshipping.com/api2.0/v1/webhook/set

# CURL

curl --location --request POST 'https://developers.cjdropshipping.com/api2.0/v1/webhook/set' \
                --header 'CJ-Access-Token: xxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
                --header 'Content-Type: application/json' \
                --data-raw '{
                    "product": {
                        "type": "ENABLE",
                        "callbackUrls": [
                            "https://your-host/api2.0/"
                        ]
                    },
                    "stock": {
                        "type": "ENABLE",
                        "callbackUrls": [
                            "https://your-host/api2.0/"
                        ]
                    },
                    "order": {
                        "type": "ENABLE",
                        "callbackUrls": [
                            "https://your-host/api2.0/"
                        ]
                    },
                    "logistics": {
                        "type": "ENABLE",
                        "callbackUrls": [
                            "https://your-host/api2.0/"
                        ]
                    },
                    "makeup": {
                        "type": "ENABLE",
                        "callbackUrls": [
                            "https://your-host/api2.0/"
                        ]
                    },
                    "privateOrder": {
                        "type": "ENABLE",
                        "callbackUrls": [
                            "https://your-host/api2.0/"
                        ]
                    }
                }'
Parameter Definition Type Required Length Note
product Product Message object Y 200 Product Message Setting
- type Product Message type string Y 200 ENABLE,CANCEL
- callbackUrls callback url string[] Y 1 Only one callback URL is supported, and it must be a reachable public HTTPS URL
stock Stock Message object Y 200 Stock Message Setting
- type Stock Message type string Y 200 ENABLE,CANCEL
- callbackUrls callback url string[] Y 1 Only one callback URL is supported, and it must be a reachable public HTTPS URL
order Order Message object Y 200 Order Message Setting
- type Message type string Y 200 ENABLE,CANCEL
- callbackUrls callback url string[] Y 1 Only one callback URL is supported, and it must be a reachable public HTTPS URL
logistics Logistics Message object Y 200 Logistics Message Setting
- type Message type string Y 200 ENABLE,CANCEL
- callbackUrls callback url string[] Y 1 Only one callback URL is supported, and it must be a reachable public HTTPS URL
makeup Makeup Bill Message object N 200 Makeup bill message setting (created/canceled/paid notifications)
- type Message type string Y 200 ENABLE,CANCEL
- callbackUrls callback url string[] Y 1 Only one callback URL is supported, and it must be a reachable public HTTPS URL
privateOrder Private Order Message object N 200 Private order (SY order / private inventory order) message setting (status-change notifications)
- type Message type string Y 200 ENABLE,CANCEL
- callbackUrls callback url string[] Y 1 Only one callback URL is supported, and it must be a reachable public HTTPS URL

# Result

success

{
    "code": 200,
    "result": true,
    "message": "Success",
    "data": true,
    "requestId": "97367e0f-cf3a-4c9b-acea-a36fb56f81b8",
    "success": true
}
Field Definition Type Length Note
code error code int 20 Reference error code
result Whether or not the return is normal boolean 1
message return message string 200
data return data object interface data return
requestId requestId string 48 Flag request for logging errors
success whether the call succeeded boolean 1 true-success, false-failed

error

{
    "code": 1607001,
    "result": false,
    "message": "Please do not use domain names such as localhost, 127.0.0.1",
    "data": null,
    "requestId": "a18c9793-7c99-42f9-970b-790eecdceba2",
    "success": false
}
Field Definition Type Length Note
code error code int 20 Reference error code
result Whether or not the return is normal boolean 1
message return message string 200
data return data object interface data return
requestId requestId string 48 Flag request for logging errors
success whether the call succeeded boolean 1 true-success, false-failed

# 2 Product Subscription

# 2.1 Subscribe Products(POST)

Subscribe specific products or enable subscribe-all mode for product/variant/stock webhook notifications.

Note: Subscribing specific products and subscribing all products are mutually exclusive.

  • If productIds is provided, only the specified products will be subscribed, and subscribe-all will be automatically disabled.
  • If only subscribeAll=true is provided (without productIds), all previously subscribed specific products will be cleared.

subscribeAll Restriction

  • Before July 2026, only users registered before June 2026 may subscribe to all products(subscribeAll=true)
  • After July 2026, subscribeAll=true will no longer be available for any user; you must specify product IDs to subscribe

# URL

https://developers.cjdropshipping.com/api2.0/v1/webhook/product/subscribe

# CURL

curl --location --request POST 'https://developers.cjdropshipping.com/api2.0/v1/webhook/product/subscribe' \
                --header 'CJ-Access-Token: xxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
                --header 'Content-Type: application/json' \
                --data-raw '{
                    "productIds": ["1952652478987366401", "1952652478987366402"],
                    "subscribeAll": false
                }'
Parameter Definition Type Required Length Note
productIds Product ID list string[] N max 100 Product IDs to subscribe. Cannot exceed subscription limit based on user level
subscribeAll Subscribe all products boolean N true=enable all products subscription, false=disable. Mutually exclusive with productIds

# Result

success

{
    "code": 200,
    "result": true,
    "message": "Success",
    "data": {
        "successProductIds": ["1952652478987366401"],
        "failProductIds": ["1952652478987366402"],
        "subscribeAll": false
    },
    "requestId": "97367e0f-cf3a-4c9b-acea-a36fb56f81b8",
    "success": true
}
Field Definition Type Length Note
code error code int 20 Reference error code
result Whether or not the return is normal boolean 1
message return message string 200
data return data object
- successProductIds Successfully subscribed product IDs string[]
- failProductIds Failed product IDs (already subscribed, not exist, etc.) string[]
- subscribeAll Whether all-products subscription is enabled boolean
requestId requestId string 48 Flag request for logging errors
success whether the call succeeded boolean 1 true-success, false-failed

error

{
    "code": 1606010,
    "result": false,
    "message": "Product webhook is not enabled",
    "data": null,
    "requestId": "a18c9793-7c99-42f9-970b-790eecdceba2",
    "success": false
}

Error Codes:

Code Message
1606010 Product webhook is not enabled
1606011 Subscription limit exceeded
1606012 Product is not subscribable
1606013 Product subscription failed

Subscription Limits by User Level:

Level Max Subscriptions
lv1 100
lv2 1000
lv3 2000
lv4 5000
lv5 10000

# 2.2 Unsubscribe Products(POST)

Remove specific products from the subscription list.

# URL

https://developers.cjdropshipping.com/api2.0/v1/webhook/product/unsubscribe

# CURL

curl --location --request POST 'https://developers.cjdropshipping.com/api2.0/v1/webhook/product/unsubscribe' \
                --header 'CJ-Access-Token: xxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
                --header 'Content-Type: application/json' \
                --data-raw '{
                    "productIds": ["1952652478987366401", "1952652478987366402"]
                }'
Parameter Definition Type Required Length Note
productIds Product ID list string[] Y max 100 Product IDs to unsubscribe

# Result

success

{
    "code": 200,
    "result": true,
    "message": "Success",
    "data": true,
    "requestId": "97367e0f-cf3a-4c9b-acea-a36fb56f81b8",
    "success": true
}
Field Definition Type Length Note
code error code int 20 Reference error code
result Whether or not the return is normal boolean 1
message return message string 200
data return data boolean 1 true=success
requestId requestId string 48 Flag request for logging errors
success whether the call succeeded boolean 1 true-success, false-failed

# 2.3 Query Subscribed Products(GET)

Query the list of subscribed products with pagination support.

# URL

https://developers.cjdropshipping.com/api2.0/v1/webhook/product/subscribe/list

# CURL

curl --location --request GET 'https://developers.cjdropshipping.com/api2.0/v1/webhook/product/subscribe/list?pageNum=1&pageSize=20&sku=CJJJJTJT00784&shopId=123456' \
                --header 'CJ-Access-Token: xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
Parameter Definition Type Required Length Note
pageNum Page number int N Default: 1, min: 1
pageSize Page size int N Default: 20, min: 1, max: 200
sku Product SPU string N 21 Optional filter by SPU
productId Product ID string N 50 Optional filter by product ID
shopId Shop ID string Y Shop ID for authorization

# Result

success

{
    "code": 200,
    "result": true,
    "message": "Success",
    "data": {
        "pageSize": 20,
        "pageNumber": 1,
        "totalRecords": 50,
        "totalPages": 3,
        "content": [
            {
                "productId": "1952652478987366401",
                "sku": "CJJJJTJT00784",
                "productName": "Wireless Bluetooth Headphone",
                "productImage": "https://cdn.cjdropshipping.com/xxx.jpg",
                "status": true,
                "reason": null,
                "createAt": "2026-04-01 10:30:00"
            }
        ]
    },
    "requestId": "97367e0f-cf3a-4c9b-acea-a36fb56f81b8",
    "success": true
}
Field Definition Type Length Note
code error code int 20 Reference error code
result Whether or not the return is normal boolean 1
message return message string 200
data return data object Pagination wrapper
- pageSize Items per page int
- pageNumber Current page int
- totalRecords Total item count int
- totalPages Total page count int
- content Product list array
-- productId Product ID string 50
-- sku Product SPU string 21
-- productName Product name string
-- productImage Product image URL string
-- status Subscription status boolean true=active, false=inactive
-- reason Inactive reason string 255 e.g. "Product delisted"
-- createAt Subscription time string Format: yyyy-MM-dd HH:mm:ss
requestId requestId string 48 Flag request for logging errors
success whether the call succeeded boolean 1 true-success, false-failed

# 3 Notification Rules

# 3.1 Product/Variant Notification Filtering

When a product or variant changes, the webhook notification is sent based on user's subscription:

  1. If user has subscribeAllProducts=true → notification is sent
  2. If user has subscribed the specific product → notification is sent
  3. Otherwise → notification is skipped

# 3.2 Stock Notification Filtering

Stock change notifications follow the same product subscription filtering rules. Only users who subscribed the corresponding product will receive stock change notifications.

# 3.3 Auto-Close Mechanism

  • Webhook success/failure counts are recorded per hour per topic
  • If the success rate in each of the previous 2 complete hours is below 80% (configurable), the webhook topic will be automatically closed
  • Auto-closed webhooks require manual re-activation
  • Close reason is recorded in the system

# 3.4 Private Inventory Outbound Order Notification

Private inventory outbound orders reuse the Order message (ORDER) topic; once the order webhook is enabled you receive them without a separate subscription:

  • A messageType=INSERT message is pushed when the private inventory outbound order is created (regular orders are not pushed on INSERT);
  • Subsequent status/payment/shipment changes are pushed as UPDATE, same as regular orders;
  • The order message params carries privateOutboundOrder=true for these orders, false for regular orders;
  • For the order message body fields, see Start - Webhook Order message.

# 4 Makeup Bill Message

After subscribing, the following makeup-bill changes are pushed to the registered makeup callback URL:

messageType Trigger params.status
INSERT Makeup bill created CREATED
CANCEL Makeup bill canceled CANCELED
PAID Makeup bill paid (completed) PAID

# 4.1 Payload Example

{
    "messageId": "f3c2a1d09e8b4c5da6b7c8d9e0f1a2b3",
    "type": "MAKEUP",
    "messageType": "PAID",
    "params": {
        "orderId": "BT2606061320024499900",
        "relationOrderId": "SD2606060858539645300",
        "payOrderId": "2605260000000001",
        "amount": 12.35,
        "reason": "Postage difference",
        "type": 1,
        "diffUseType": 0,
        "status": "PAID",
        "createDate": "2026-06-04 10:00:00",
        "paymentDate": "2026-06-04 12:00:00"
    }
}

Order number notes: orderId is the makeup bill number, always BT-prefixed (e.g. BT2606061320024499900), same as orderCode in the makeup list; relationOrderId is the original CJ order being made up — its type depends on the original order (private inventory outbound SD…, dropshipping/direct, etc.) and can be used to look up the original order via the order query API.

Field Type Description
messageId string Unique message ID (unchanged on retry, usable for idempotent dedup)
type string Business type, always MAKEUP
messageType string INSERT created / CANCEL canceled / PAID paid
params.orderId string Makeup bill number, BT prefix, same as orderCode in the makeup list, e.g. BT2606061320024499900
params.relationOrderId string Original CJ order number being made up; type varies (private inventory outbound SD…, dropshipping/direct, etc.), e.g. SD2606060858539645300
params.payOrderId string Makeup payment order number (returned after payment)
params.amount number Makeup amount in USD
params.reason string Makeup reason (English)
params.type int 1 = makeup
params.diffUseType int 0=order makeup 1=Balance Top-up 2=Repayment 3=Transfer Shipping Fee
params.status string CREATED / CANCELED / PAID
params.createDate string Create time yyyy-MM-dd HH:mm:ss
params.paymentDate string Payment time (returned when PAID)

# 4.2 Signature Verification

The request carries a sign header: sign = Base64( HmacSHA256( secret = your openId string, message = raw JSON request body ) ). Compute HmacSHA256 over the raw body with your openId as the secret, Base64-encode it, and compare with the sign header.

# 4.3 Response Requirements

Same as other topics: return 200 OK within 3 seconds; failed pushes are retried (up to 3 times); continuous failures trigger the auto-close mechanism (see 3.3).

# 5 Private Order Message (PrivateOrder)

After subscribing the privateOrder topic, status changes of private orders (SY order / private inventory order, order number prefixed with SY) are pushed to the registered callback URL. Only SY orders are pushed (dropshipping/deposit orders are excluded).

messageType Trigger
UPDATE SY order status changes (e.g. awaiting payment → paid → awaiting dispatch → dispatched → completed/canceled)

# 5.1 Payload Example

{
    "messageId": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
    "type": "PRIVATE_ORDER",
    "messageType": "UPDATE",
    "params": {
        "orderId": "SY2606061320024499900",
        "orderNumber": "shop_order_123",
        "status": "SHIPPED",
        "orderType": 2,
        "createDate": "2026-06-04 10:00:00",
        "paymentDate": "2026-06-04 12:00:00",
        "deliveryDate": "2026-06-05 09:00:00",
        "completeDate": null
    }
}
Field Type Description
messageId string Unique message ID (unchanged on retry, usable for idempotent dedup)
type string Business type, always PRIVATE_ORDER
messageType string UPDATE - status change
params.orderId string Private order number. Number rule: fixed SY prefix + 19-digit number (snowflake id), e.g. SY2606061320024499900
params.orderNumber string Store order number
params.status string Order status name, see 5.2
params.orderType int Order type: 2=stock-up (private inventory order / SY order). The private-order webhook currently only pushes SY orders, so orderType is always 2
params.createDate string Create time yyyy-MM-dd HH:mm:ss
params.paymentDate string Payment time (returned when paid)
params.deliveryDate string Dispatch (outbound) time (returned when shipped)
params.completeDate string Completion time (returned when completed)

# 5.2 status values

status Description
WAIT_PAY Awaiting payment
PAYMENT_INCOMING Payment incoming
PAID Paid, pending
WAIT_SHIPMENT Awaiting dispatch
INTERCEPTING / INTERCEPT Intercepting / intercepted
SHIPPED Dispatched
COMPLETED Completed
OVER Closed
CANCELLED Canceled
REFUND_COMPLETE Dispute refund completed
RESEND_OVER Dispute resend completed

# 5.3 Signature & Response

Same as other topics: sign = Base64( HmacSHA256( secret = your openId string, message = raw JSON request body ) ); return 200 OK within 3 seconds; failed pushes are retried (up to 3 times); continuous failures trigger the auto-close mechanism (see 3.3).