⚡ Try It — API Credentials (enter once, used by all endpoints below)
🚀

Getting Started

#getting-started

The CHUB API lets you programmatically manage your warehouse operations. Your API credentials are generated by your CHUB account manager from the admin panel — once issued, you can view your API Token and API Secret at any time by logging into your client portal and going to Settings.

All API calls must be made over HTTPS. Requests over plain HTTP will be rejected. All request and response bodies are encoded as JSON.

Base URL https://chub.ae/api/v1
💡
Quick tip: Include an X-Request-ID header with a unique UUID in every request. CHUB echoes it back in all responses — making it much easier to correlate logs and debug issues across distributed systems.

Your First Request

cURL
JavaScript
PHP
Python
Go
Check your first SKU
curl -X GET \
  https://chub.ae/api/v1/product-stock/YOUR-SKU-HERE \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret" \
  -H "Accept: application/json"
const response = await fetch('https://chub.ae/api/v1/product-stock/YOUR-SKU-HERE', {
  headers: {
    'X-CHUB-TOKEN': 'your_api_token',
    'X-CHUB-SECRET': 'your_api_secret',
    'Accept': 'application/json',
  }
});
const data = await response.json();
console.log(data);
$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL            => 'https://chub.ae/api/v1/product-stock/YOUR-SKU-HERE',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => [
    'X-CHUB-TOKEN: your_api_token',
    'X-CHUB-SECRET: your_api_secret',
    'Accept: application/json',
  ],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
import requests

headers = {
    'X-CHUB-TOKEN':  'your_api_token',
    'X-CHUB-SECRET': 'your_api_secret',
    'Accept':        'application/json',
}

res = requests.get(
    'https://chub.ae/api/v1/product-stock/YOUR-SKU-HERE',
    headers=headers
)
print(res.json())
package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET",
        "https://chub.ae/api/v1/product-stock/YOUR-SKU-HERE", nil)
    req.Header.Set("X-CHUB-TOKEN",  "your_api_token")
    req.Header.Set("X-CHUB-SECRET", "your_api_secret")
    req.Header.Set("Accept",        "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
🔐

Authentication

#authentication

The CHUB API uses a dual-credential scheme. Every authenticated request must include both headers simultaneously. Missing either will result in a 401 Unauthorized response.

X-CHUB-TOKEN Your client API token — identifies your account
X-CHUB-SECRET Your client API secret — signs and validates the request
X-Request-ID Optional UUID for request tracing — strongly recommended
⚠️
Keep credentials secret. Never expose your token or secret in client-side code, public repositories, or logs. Treat them like passwords. To rotate credentials, contact your account manager or use the portal's API Keys section.
Authentication headers example
# Required on every authenticated request
X-CHUB-TOKEN: tok_live_a1b2c3d4e5f6...
X-CHUB-SECRET: sec_live_x7y8z9w0v1u2...
Content-Type: application/json
Accept: application/json

# Recommended for tracing
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
⏱️

Rate Limiting

#rate-limiting

API requests are rate-limited to protect platform stability. Limits apply per API token.

Client API 300 requests / minute
Window 60 seconds (rolling)
Bulk SKU Limit 200 SKUs per request

When rate-limited, the API returns 429 Too Many Requests. Implement exponential backoff with jitter when handling 429 responses.

📦

Orders API

POST /api/v1/orders Create a new order

Submit a new fulfillment order. CHUB will validate stock availability for all line items. If any item has insufficient stock, the order is placed with an on_hold_stock status and an issues array is returned detailing the affected SKUs.

Request Body

Field Type Required Description
order_numberstringoptionalYour own reference number. Auto-generated if omitted.
customer_namestringrequiredFull name of the recipient
customer_phonestringoptionalUAE format (05XXXXXXXX). Nullable.
customer_emailstringoptionalRecipient email for notifications
countrystringoptionalDefaults to "United Arab Emirates"
citystringrequiredDelivery city
areastringrequiredDelivery area / district
streetstringoptionalStreet name or number
buildingstringoptionalBuilding name or number
apartment_nostringoptionalApartment / unit number
landmarkstringoptionalNearby landmark for the courier
full_addressstringoptionalFull address override. Auto-built from the above fields if omitted.
payment_typestringrequiredcod or prepaid
delivery_chargenumberoptionalDelivery fee in AED. Defaults to 0.
notesstringoptionalSpecial delivery instructions
itemsarrayrequiredArray of order line items (see below)
items[].skustringrequiredProduct SKU — case-insensitive
items[].quantityintegerrequiredQuantity (min 1)
cURL
JavaScript
PHP
Python
Go
POST /api/v1/orders
curl -X POST \
  https://chub.ae/api/v1/orders \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "order_number": "MY-ORD-001",
    "customer_name": "Ahmed Al Mansoori",
    "customer_phone": "0501234567",
    "customer_email": "[email protected]",
    "city": "Dubai",
    "area": "Al Barsha",
    "street": "Sheikh Zayed Rd",
    "building": "Villa 12",
    "payment_type": "cod",
    "delivery_charge": 15.00,
    "notes": "Leave at door",
    "items": [
      { "sku": "PROD-001", "quantity": 2 },
      { "sku": "PROD-002", "quantity": 1 }
    ]
  }'
const res = await fetch('https://chub.ae/api/v1/orders', {
  method: 'POST',
  headers: {
    'X-CHUB-TOKEN':  'your_api_token',
    'X-CHUB-SECRET': 'your_api_secret',
    'Content-Type':  'application/json',
    'Accept':        'application/json',
  },
  body: JSON.stringify({
    order_number:    'MY-ORD-001',       // optional — auto-generated if omitted
    customer_name:   'Ahmed Al Mansoori',
    customer_phone:  '0501234567',         // optional
    customer_email:  '[email protected]',   // optional
    city:            'Dubai',
    area:            'Al Barsha',
    street:          'Sheikh Zayed Rd',    // optional
    building:        'Villa 12',           // optional
    payment_type:    'cod',
    delivery_charge: 15.00,               // optional, defaults to 0
    notes:           'Leave at door',      // optional
    items: [
      { sku: 'PROD-001', quantity: 2 },
      { sku: 'PROD-002', quantity: 1 },
    ],
  }),
});
const order = await res.json();
$payload = [
  'order_number'    => 'MY-ORD-001',          // optional
  'customer_name'   => 'Ahmed Al Mansoori',
  'customer_phone'  => '0501234567',           // optional
  'customer_email'  => '[email protected]',    // optional
  'city'            => 'Dubai',
  'area'            => 'Al Barsha',
  'street'          => 'Sheikh Zayed Rd',      // optional
  'building'        => 'Villa 12',             // optional
  'payment_type'    => 'cod',
  'delivery_charge' => 15.00,                 // optional
  'notes'           => 'Leave at door',       // optional
  'items'           => [
    ['sku' => 'PROD-001', 'quantity' => 2],
    ['sku' => 'PROD-002', 'quantity' => 1],
  ],
];

$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL            => 'https://chub.ae/api/v1/orders',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST           => true,
  CURLOPT_POSTFIELDS     => json_encode($payload),
  CURLOPT_HTTPHEADER     => [
    'X-CHUB-TOKEN: your_api_token',
    'X-CHUB-SECRET: your_api_secret',
    'Content-Type: application/json',
    'Accept: application/json',
  ],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
import requests

payload = {
    "order_number":    "MY-ORD-001",           # optional
    "customer_name":   "Ahmed Al Mansoori",
    "customer_phone":  "0501234567",            # optional
    "customer_email":  "[email protected]",     # optional
    "city":            "Dubai",
    "area":            "Al Barsha",
    "street":          "Sheikh Zayed Rd",       # optional
    "building":        "Villa 12",              # optional
    "payment_type":    "cod",
    "delivery_charge": 15.00,                  # optional
    "notes":           "Leave at door",         # optional
    "items": [
        { "sku": "PROD-001", "quantity": 2 },
        { "sku": "PROD-002", "quantity": 1 },
    ],
}
headers = {
    "X-CHUB-TOKEN":  "your_api_token",
    "X-CHUB-SECRET": "your_api_secret",
    "Accept":        "application/json",
}
res = requests.post(
    "https://chub.ae/api/v1/orders",
    json=payload,
    headers=headers
)
print(res.json())
package main

import (
    "bytes"; "encoding/json"; "fmt"
    "io";    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]any{
        "customer_name":   "Ahmed Al Mansoori",
        "customer_phone":  "0501234567",
        "customer_email":  "[email protected]",
        "city":            "Dubai",
        "area":            "Al Barsha",
        "street":          "Sheikh Zayed Rd",
        "building":        "Villa 12",
        "payment_type":    "cod",
        "delivery_charge": 15.00,
        "items": []map[string]any{
            {"sku": "PROD-001", "quantity": 2},
            {"sku": "PROD-002", "quantity": 1},
        },
    })
    req, _ := http.NewRequest("POST",
        "https://chub.ae/api/v1/orders",
        bytes.NewBuffer(body))
    req.Header.Set("X-CHUB-TOKEN",  "your_api_token")
    req.Header.Set("X-CHUB-SECRET", "your_api_secret")
    req.Header.Set("Content-Type",   "application/json")
    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    out, _ := io.ReadAll(resp.Body)
    fmt.Println(string(out))
}

Response — 201 Created

Success response
{
  "success": true,
  "message": "Order created successfully.",
  "order_id": 1042,
  "order_number": "AH-00001",
  "status": "pending",
  "issues": [],   // Empty = all items in stock
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Response — 201 with Stock Issues

Partial stock — order placed on hold
{
  "success": true,
  "message": "Order created with stock issues.",
  "order_id": 1043,
  "order_number": "AH-00002",
  "status": "on_hold_stock",
  "issues": [
    {
      "type": "INSUFFICIENT_STOCK",
      "sku": "PROD-002",
      "product_name": "Blue Hoodie XL",
      "requested": 5,
      "available": 2,
      "missing": 3
    }
  ],
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
PATCH /api/v1/orders/{order_number} Modify a pending order

Update an existing order. Only orders with status pending or on_hold_stock can be modified. Attempting to update a processing or dispatched order returns a 422 error.

⚠️
Updating items replaces the entire item list — it is not a diff/patch. Send the complete desired item list each time.

Request Body (all fields optional)

FieldTypeRequiredDescription
itemsarrayoptionalReplaces the entire item list when provided
items[].skustringrequiredProduct SKU — case-insensitive
items[].quantityintegerrequiredQuantity (min 1)
delivery_chargenumberoptionalUpdated delivery fee in AED
payment_typestringoptionalcod or prepaid
notesstringoptionalUpdated delivery instructions
PATCH /api/v1/orders/AH-240001
curl -X PATCH \
  https://chub.ae/api/v1/orders/AH-240001 \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "delivery_charge": 20.00,
    "payment_type": "prepaid",
    "items": [
      { "sku": "PROD-001", "quantity": 3 },
      { "sku": "PROD-003", "quantity": 1 }
    ]
  }'

Response — 200 OK

{
  "success": true,
  "message": "Order updated successfully.",
  "order_number": "AH-00001",
  "status": "pending",
  "total_items": 4,
  "total_amount": "310.00",
  "issues": [],
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
GET /api/v1/order-status/{order_number} Get order status

Retrieve the current fulfillment status of an order. Use this to poll for status changes or build real-time tracking into your storefront.

GET /api/v1/order-status/AH-240001
curl https://chub.ae/api/v1/order-status/AH-240001 \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret"

Response — 200 OK

{
  "success": true,
  "order_number": "AH-00001",
  "status": "on_the_way",
  "last_updated": "2024-11-14T09:32:00.000000Z"
}
📦

Products API

POST /api/v1/products Create a new product in CHUB

Creates a new product linked to your account. SKU must be unique within your catalog. Stock quantity is managed by CHUB warehouse staff — it cannot be set via this API and always starts at 0.

FieldTypeRequiredDescription
skustringrequiredUnique product identifier. Max 100 characters.
namestringrequiredProduct display name. Max 255 characters.
product_typestringoptionale.g. simple, bundle. Defaults to simple.
sale_pricenumberoptionalSelling price (used for order value calculation).
cost_pricenumberoptionalCost / landed price.
barcodestringoptionalEAN, UPC or any barcode string.
external_product_idstringoptionalYour internal ID (Shopify product ID, WooCommerce ID, etc.).
weight_gramsintegeroptionalWeight in grams.
length_cmnumberoptionalLength in centimetres.
width_cmnumberoptionalWidth in centimetres.
height_cmnumberoptionalHeight in centimetres.
country_of_originstringoptional2-letter ISO country code (e.g. AE, CN, US).
hs_codestringoptionalHarmonised System code for customs. Max 20 characters.
image_urlstring (URL)optionalPublic URL of the product image on your CDN.
descriptionstringoptionalProduct description.
cURL
JavaScript
POST /api/v1/products
curl -X POST \
  https://chub.ae/api/v1/products \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "sku": "PROD-001",
    "name": "Premium Wireless Headphones",
    "product_type": "simple",
    "sale_price": 299.00,
    "cost_price": 120.00,
    "barcode": "6291041500213",
    "external_product_id": "shopify_8821934",
    "weight_grams": 350,
    "length_cm": 20,
    "width_cm": 18,
    "height_cm": 9,
    "country_of_origin": "CN",
    "image_url": "https://cdn.yourstore.com/products/headphones.jpg",
    "description": "Over-ear noise cancelling headphones"
  }'
const res = await fetch('https://chub.ae/api/v1/products', {
  method: 'POST',
  headers: {
    'X-CHUB-TOKEN': 'your_api_token',
    'X-CHUB-SECRET': 'your_api_secret',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    sku: 'PROD-001',
    name: 'Premium Wireless Headphones',
    sale_price: 299.00,
    external_product_id: 'shopify_8821934',
    image_url: 'https://cdn.yourstore.com/products/headphones.jpg',
  }),
});
const { data } = await res.json();
console.log(data.sku);

Response — 201 Created

{
  "success": true,
  "message": "Product created successfully.",
  "data": {
    "sku": "PROD-001",
    "name": "Premium Wireless Headphones",
    "product_type": "simple",
    "sale_price": "299.00",
    "cost_price": "120.00",
    "available_qty": 0,
    "barcode": "6291041500213",
    "external_product_id": "shopify_8821934",
    "weight_grams": 350,
    "length_cm": "20.00",
    "width_cm": "18.00",
    "height_cm": "9.00",
    "country_of_origin": "CN",
    "hs_code": null,
    "image_url": "https://cdn.yourstore.com/products/headphones.jpg",
    "description": "Over-ear noise cancelling headphones",
    "created_at": "2026-03-31T10:00:00.000000Z",
    "updated_at": "2026-03-31T10:00:00.000000Z"
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Error Codes

HTTPerror_codeMeaning
422VALIDATION_ERROROne or more fields failed validation
409DUPLICATE_SKUA product with this SKU already exists in your catalog
500SERVER_ERRORUnexpected server error
PUT /api/v1/products/{sku} Update an existing product

Updates an existing product by SKU. All fields are optional — only the fields you send will be updated (partial update). The sku itself and available_qty cannot be changed via this endpoint.

FieldTypeRequiredDescription
namestringoptionalUpdated product name.
product_typestringoptionale.g. simple, bundle.
sale_pricenumberoptionalUpdated selling price.
cost_pricenumberoptionalUpdated cost price.
barcodestringoptionalUpdated barcode.
external_product_idstringoptionalUpdated external ID.
weight_gramsintegeroptionalUpdated weight in grams.
length_cmnumberoptionalUpdated length.
width_cmnumberoptionalUpdated width.
height_cmnumberoptionalUpdated height.
country_of_originstringoptional2-letter ISO country code.
hs_codestringoptionalUpdated HS code.
image_urlstring (URL)optionalUpdated product image URL.
descriptionstringoptionalUpdated description.
cURL
JavaScript
PUT /api/v1/products/PROD-001
curl -X PUT \
  https://chub.ae/api/v1/products/PROD-001 \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "sale_price": 249.00,
    "image_url": "https://cdn.yourstore.com/products/headphones-v2.jpg"
  }'
const res = await fetch('https://chub.ae/api/v1/products/PROD-001', {
  method: 'PUT',
  headers: {
    'X-CHUB-TOKEN': 'your_api_token',
    'X-CHUB-SECRET': 'your_api_secret',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    sale_price: 249.00,
    image_url: 'https://cdn.yourstore.com/products/headphones-v2.jpg',
  }),
});
const { data } = await res.json();
console.log(data.sale_price);

Response — 200 OK

{
  "success": true,
  "message": "Product updated successfully.",
  "data": {
    "sku": "PROD-001",
    "name": "Premium Wireless Headphones",
    "product_type": "simple",
    "sale_price": "249.00",
    "available_qty": 142,
    "image_url": "https://cdn.yourstore.com/products/headphones-v2.jpg",
    "updated_at": "2026-03-31T11:30:00.000000Z"
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Error Codes

HTTPerror_codeMeaning
404PRODUCT_NOT_FOUNDNo product with this SKU exists in your catalog
422VALIDATION_ERROROne or more fields failed validation
422NO_CHANGESRequest body contained no updatable fields
500SERVER_ERRORUnexpected server error
📊

Stock API

GET /api/v1/product-stock/{sku} Get stock for a single SKU

Returns the current available quantity for a single SKU. SKU lookups are case-insensitive — the response returns the SKU exactly as stored in the system.

cURL
JavaScript
GET /api/v1/product-stock/PROD-001
curl https://chub.ae/api/v1/product-stock/PROD-001 \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret"
const res = await fetch(
  'https://chub.ae/api/v1/product-stock/PROD-001',
  { headers: { 'X-CHUB-TOKEN': '...', 'X-CHUB-SECRET': '...' } }
);
const { data } = await res.json();
console.log(`Available: ${data.quantity}`);

Response — 200 OK

{
  "success": true,
  "data": {
    "sku": "PROD-001",
    "quantity": 142,
    "updated_at": "2024-11-14T08:00:00.000000Z"
  }
}
POST /api/v1/product-stock Bulk stock lookup (up to 200 SKUs)

Query stock levels for up to 200 SKUs in a single request. The response includes a missing array with any SKUs that were not found in your catalog.

FieldTypeRequiredDescription
skusarray<string>requiredList of SKUs to query. Max 200.
POST /api/v1/product-stock
curl -X POST \
  https://chub.ae/api/v1/product-stock \
  -H "X-CHUB-TOKEN: your_api_token" \
  -H "X-CHUB-SECRET: your_api_secret" \
  -H "Content-Type: application/json" \
  -d '{ "skus": ["PROD-001", "PROD-002", "PROD-003", "UNKNOWN-SKU"] }'

Response — 200 OK

{
  "success": true,
  "data": [
    { "sku": "PROD-001", "quantity": 142, "updated_at": "2024-11-14T08:00:00Z" },
    { "sku": "PROD-002", "quantity": 0,   "updated_at": "2024-11-13T14:22:00Z" },
    { "sku": "PROD-003", "quantity": 56,  "updated_at": "2024-11-14T07:45:00Z" }
  ],
  "missing": ["UNKNOWN-SKU"]  // SKUs not found in your catalog
}
📄

Response Format

#response-format

All API responses use a consistent JSON envelope. Always check the success field before parsing data.

FieldTypeDescription
successbooleantrue on 2xx responses, false on errors
messagestringHuman-readable summary
dataobject | arrayResponse payload. Present on success.
errorsobjectValidation error details. Present on 422.
error_codestringMachine-readable error identifier
issuesarrayStock or fulfillment warnings on order creation
request_idstringEcho of your X-Request-ID header
Error response example — 422 Validation Error
{
  "success": false,
  "message": "Validation failed",
  "error_code": "VALIDATION_ERROR",
  "errors": {
    "customer_phone": ["The customer phone field is required."],
    "items.0.sku": ["The items.0.sku field is required."]
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
🔄

Order Statuses

#order-statuses

Orders progress through the following lifecycle states. The status returned by the API reflects real-time warehouse activity.

pending on_hold_stock processing picked packed ready_dispatch on_the_way delivered cancelled
StatusDescriptionModifiable
pendingOrder received and queued for picking✅ Yes
on_hold_stockPlaced on hold due to insufficient stock✅ Yes
processingPicker has started fulfilling the order❌ No
pickedAll items picked from warehouse shelves❌ No
packedOrder packed and labeled❌ No
ready_dispatchAwaiting courier pickup❌ No
on_the_wayWith courier for last-mile delivery❌ No
deliveredSuccessfully delivered to customer❌ No
cancelledOrder cancelled❌ No
⚡

HTTP Status Codes

#http-codes
200
OK
Request succeeded. Data returned in body.
201
Created
Resource created. Returned on order creation.
401
Unauthorized
Missing or invalid API credentials.
404
Not Found
Order or SKU not found.
409
Conflict
Duplicate order number for this client.
422
Unprocessable
Validation failed. Check errors field.
429
Too Many Requests
Rate limit exceeded. Retry after a moment.
500
Server Error
Unexpected error. Contact support with request_id.
🔴

Error Codes

#error-codes

Machine-readable error codes are returned in the error_code field. Use these for programmatic error handling in your integration.

VALIDATION_ERROR 422 One or more request fields failed validation. Check errors object.
INVALID_SKU 422 One or more SKUs in the request are not registered in your catalog.
INSUFFICIENT_STOCK 422 Stock is below the requested quantity. Returned in issues array with details.
DUPLICATE_ORDER 409 An order with this number already exists for your account.
ORDER_NOT_FOUND 404 No order with the specified order number found for your account.
ORDER_NOT_MODIFIABLE 422 Order is in a non-editable state (processing or beyond).
SERVER_ERROR 500 Unexpected server-side error. Include your request_id when contacting support.
CHUB Warehouse API Reference
Last updated 06 Oct 2026, 08:52 GST
Need help? Email [email protected]