Open API

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 example GET or POST.
  • PATH contains only the request path, excluding domain and query string, for example /openapi/v1/orders.
  • RAW_BODY must be the exact HTTP request body. For GET requests with no body, hash an empty string.
  • X-Signature is the lowercase hexadecimal result of hash_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

Amounts

All amount fields are in USD cents and usually end with *_usd_cents. For example, 1234 means $12.34.

Idempotency

When creating an order, external_order_no must be unique under the current account. Also send Idempotency-Key when possible.

Content-Type

POST requests use application/json. GET parameters are sent through the query string.

Responses

All endpoints return code, message, and data. Success uses code=200.

Success Response Format

{
  "code": 200,
  "message": "success",
  "data": {}
}

Account Balance

GET /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

GET /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

POST /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

POST /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

GET /openapi/v1/orders/{externalOrderNo}

Query order status, amounts, and package information by partner order number.

Tracking

GET /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, and AppSecret.
  • 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_no and Idempotency-Key.
  • All amounts are handled in USD cents to avoid floating-point errors.