Open API Documentation
This guide is for third-party partners integrating with JYC ERP through an Open API account. It covers product lookup, order preview, balance-based order creation, and shipment tracking.
Before integration, contact your account manager to create an Open API account. Each account receives an AppKey and AppSecret; allowed companies, warehouses, IP allowlist, and account balance are configured by JYC.
Environment URLs
| Environment | API Base URL | Description |
|---|---|---|
| Test | https://test-api.example.com |
Use the actual URL provided by your account manager. |
| Production | https://jyc-api.example.com |
Use the actual URL provided by your account manager. |
Authentication
All /openapi/v1 endpoints require signed request headers.
| Header | Required | Description |
|---|---|---|
X-App-Key |
Yes | Open API account AppKey. |
X-Timestamp |
Yes | Unix timestamp in seconds. The default allowed clock skew is 5 minutes. |
X-Nonce |
Yes | Random string. It must not be reused for the same AppKey within the replay window. |
X-Signature |
Yes | HMAC-SHA256 signature generated with the AppSecret. |
X-Request-Id |
No | Client-side request ID for troubleshooting. If omitted, the server generates one. |
Idempotency-Key |
Recommended | Idempotency key for order creation. Repeated requests return the original result. |
String to Sign
METHOD + "\n" +
PATH + "\n" +
TIMESTAMP + "\n" +
NONCE + "\n" +
SHA256(RAW_BODY)
Notes:
- Use uppercase
METHOD, for exampleGETorPOST. PATHcontains only the request path, excluding domain and query string, for example/openapi/v1/orders.RAW_BODYmust be the exact HTTP request body. For GET requests with no body, hash an empty string.X-Signatureis the lowercase hexadecimal result ofhash_hmac('sha256', stringToSign, AppSecret).
Node.js Signature Example
const crypto = require('crypto')
function sign({ method, path, timestamp, nonce, body, appSecret }) {
const rawBody = body || ''
const bodyHash = crypto.createHash('sha256').update(rawBody).digest('hex')
const payload = [
method.toUpperCase(),
path,
String(timestamp),
nonce,
bodyHash,
].join('\n')
return crypto.createHmac('sha256', appSecret).update(payload).digest('hex')
}
PHP Signature Example
function openApiSign(string $method, string $path, string $timestamp, string $nonce, string $rawBody, string $appSecret): string
{
$payload = strtoupper($method) . "\n"
. $path . "\n"
. $timestamp . "\n"
. $nonce . "\n"
. hash('sha256', $rawBody);
return hash_hmac('sha256', $payload, $appSecret);
}
Conventions
All amount fields are in USD cents and usually end with *_usd_cents. For example, 1234 means $12.34.
When creating an order, external_order_no must be unique under the current account. Also send Idempotency-Key when possible.
POST requests use application/json. GET parameters are sent through the query string.
All endpoints return code, message, and data. Success uses code=200.
Success Response Format
{
"code": 200,
"message": "success",
"data": {}
}
Account Balance
/openapi/v1/account/balance
Returns the current account balance and available amount.
{
"code": 200,
"message": "success",
"data": {
"account_id": 1,
"name": "Partner A",
"balance_usd_cents": 100000,
"credit_limit_usd_cents": 0,
"available_usd_cents": 100000
}
}
Products
/openapi/v1/products
| Parameter | Type | Required | Description |
|---|---|---|---|
page |
int | No | Page number. Default: 1. |
page_size |
int | No | Page size. Default: 20. Maximum: 100. |
warehouse_id |
int | No | Warehouse ID. If omitted, products from all warehouses allowed for the account are returned. |
keyword |
string | No | Search by product name or short code. |
{
"code": 200,
"message": "success",
"data": {
"list": [
{
"product_id": 1001,
"short_code": "ABC",
"product_name": "Product A",
"product_spec": "10mg",
"warehouse_id": 1,
"stock": 50,
"weight_grams": 100,
"unit_price_usd_cents": 1200,
"is_promotion": 0
}
],
"total": 1
}
}
Order Preview
/openapi/v1/orders/preview
Calculates product amount, shipping fee, total amount, and checks stock shortage or review status before creating the order.
{
"external_order_no": "TP202605290001",
"warehouse_id": 1,
"shipping_method": "zhang",
"customer_name": "John",
"contact_type": "phone",
"contact_value": "123456",
"delivery_address": "Address line",
"remark": "Partner order",
"items": [
{
"product_id": 1001,
"quantity": 2
}
]
}
{
"code": 200,
"message": "success",
"data": {
"external_order_no": "TP202605290001",
"status": "waiting_shipment",
"presale_flag": 0,
"anomaly_flag": 0,
"goods_amount_usd_cents": 2400,
"shipping_amount_usd_cents": 800,
"total_amount_usd_cents": 3200,
"linked_amount_usd_cents": 0,
"payment_links": []
}
}
Create Order
/openapi/v1/orders
Creating an order deducts the amount from the Open API account balance and creates a confirmed Open API Balance payment record in ERP.
Send Idempotency-Key when creating orders. If a timeout occurs and the result is unknown, retry with the same external_order_no or the same idempotency key. Do not submit a duplicate order with a new order number.
| Field | Type | Required | Description |
|---|---|---|---|
external_order_no |
string | Yes | Partner order number. It must be unique under the current account. |
warehouse_id |
int | No | If omitted, the account default warehouse is used. |
shipping_method |
string | Yes | Shipping method, for example zhang or jia. Use the values configured for your account. |
customer_name |
string | Yes | Customer name. |
contact_type |
string | No | Contact type. |
contact_value |
string | No | Contact value. |
delivery_address |
string | Yes | Delivery address. |
items |
array | Yes | Order item array. |
{
"external_order_no": "TP202605290001",
"warehouse_id": 1,
"shipping_method": "zhang",
"customer_name": "John",
"contact_type": "phone",
"contact_value": "123456",
"delivery_address": "Address line",
"remark": "Partner order",
"confirm_presale": false,
"items": [
{
"product_id": 1001,
"quantity": 2
}
]
}
{
"code": 200,
"message": "success",
"data": {
"external_order_no": "TP202605290001",
"order_id": 123,
"order_number": "V2605290001",
"customer_order_number": "C2605290001",
"status": "waiting_shipment",
"amount_usd_cents": 3200,
"payment_id": 456,
"balance_usd_cents": 96800,
"goods_amount_usd_cents": 2400,
"shipping_amount_usd_cents": 800,
"total_amount_usd_cents": 3200,
"packages": [],
"created_at": "2026-05-29 12:00:00"
}
}
Order Detail
/openapi/v1/orders/{externalOrderNo}
Query order status, amounts, and package information by partner order number.
Tracking
/openapi/v1/orders/{externalOrderNo}/tracking
{
"code": 200,
"message": "success",
"data": {
"external_order_no": "TP202605290001",
"order_number": "V2605290001",
"status": "in_transit",
"packages": [
{
"carrier": "Carrier",
"tracking_number": "TRACK123",
"tracking_image": "",
"shipped_at": "2026-05-30 10:00:00"
}
]
}
}
Error Handling
For business failures, the HTTP status is usually still 200, but response code is not 200. Client systems should primarily check the response body code.
| Scenario | Message Example | Recommended Action |
|---|---|---|
| Invalid signature | Open API signature is invalid | Check the string to sign, AppSecret, and raw request body. |
| Expired request | Open API request has expired | Check server clock synchronization. |
| Duplicate nonce | Open API nonce has already been used | Generate a new random nonce for each request. |
| Insufficient balance | Open API account balance is insufficient | Contact your account manager to top up the balance, or retry with a lower order amount. |
| Insufficient stock | Insufficient stock. The order must be submitted as a pre-order. | Confirm whether pre-orders are allowed. If allowed, retry with confirm_presale=true. |
Failure Response Example
{
"code": 500,
"message": "Open API account balance is insufficient",
"data": []
}
Integration Checklist
- You have received the production
Base URL,AppKey, andAppSecret. - Your server outbound IP has been provided to JYC for allowlisting.
- Call order preview before creating an order to confirm the amount.
- Order creation implements idempotent retry with
external_order_noandIdempotency-Key. - All amounts are handled in USD cents to avoid floating-point errors.