SKYBIZ API Setup – Standard

  10. API Documentation
How to connect and use the SKYBIZ API Version 2.0

Introduction

This guide is for developers and POS vendors who want to quickly get started with the SKYBIZ API. It covers the essential steps such as getting your credentials, making your first request, and understanding the responses.

For full technical details, field references, and error documentation, refer to the SKYBIZ API Setup (Advanced).

Target Audience: POS software vendors / Integration developers


Before You Begin

Make sure the following are ready before you start:

  • API Integration is enabled by your SKYBIZ administrator (Mode 1 = Production, Mode 2 = Developer)
  • You have a Callback URL that is publicly accessible and can receive POST requests
  • You have access to a REST client such as Postman for testing

Step 1 — Set Up Your Callback URL

  • You must use publicly accessible Callback URL in order to receive your API Key and Secret Key
  • You can also use public Webhook Request Bin that acts as a temporary, public endpoint that allows you to inspect, debug, and test HTTP requests and webhooks in real-time.

Sample Code for receiving the Keys using Callback URL

<?php
// callback.php
// Place this file on your server and use its URL as your callback_url during registration
// Example: https://yourdomain.com/callback.php


// ============================================================
// STEP 1 — Read the raw request body from SKYBIZ
// ============================================================
$rawBody = file_get_contents('php://input');
$headers = getallheaders();
$timestamp = $headers['X-Timestamp'] ?? '';
$signature = $headers['X-Signature'] ?? '';

// ============================================================
// STEP 2 — Decode the JSON payload
// ============================================================
$payload = json_decode($rawBody, true);

if (!$payload || !isset($payload['api_key'], $payload['api_secret'])) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Invalid payload']);
exit;
}

$apiKey = $payload['api_key'];
$apiSecret = $payload['api_secret'];

// ============================================================
// STEP 3 — Verify the signature
// This confirms the request is genuinely from SKYBIZ
// ============================================================
$expectedSignature = hash_hmac('sha256', $timestamp . '.' . $rawBody, $apiSecret);

if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Signature verification failed']);
exit;
}

// ============================================================
// STEP 4 — Store the credentials SECURELY
// 
// ⚠️ This is the ONLY time the api_secret is in plain text.
// Save it now. SKYBIZ will NOT send it again.
//
// Options:
// A) Write to a secure .env file
// B) Save to your database (encrypted)
// C) Push to your secrets manager
//
// The example below writes to a .env file.
// ============================================================
$envContent = "SKYBIZ_API_KEY={$apiKey}\nSKYBIZ_API_SECRET={$apiSecret}\n";

// Make sure this path is OUTSIDE your public web root
$envPath = __DIR__ . '/../../secure/.env';

file_put_contents($envPath, $envContent);

// ============================================================
// STEP 5 — Respond with 200 OK so SKYBIZ knows delivery was successful
// ============================================================
http_response_code(200);
echo json_encode(['status' => 'received']);
exit;


Guide to receive the Keys using Webhook.site

1.Go to Webhook.site

2.Copy your unique URL and use it when registering your credentials as your Callback URL later in Step 2 – Register Your Credentials.


Step 2 — Register Your Credentials

  1. Navigate to API Credentials Section in SKYBIZ Portal

2. Click the New Credentials Button on the right side of the API Credentials Section

4. The New API Credentials Popup will be displayed

5. Select the Integration Type – API Key

6. Insert your public Callback URL or Newly Copied URL From Webhook.site

7. Click the Create Credentials Button

8. The API Key and Secret Key will be sent to your Callback URL

{
"api_key": "a1b2c3d4e5f6a1b2c3d4e5f67",
"api_secret": "your-64-character-secret-here"
}

9. If you are using Webhook.site, the keys will be sent and you can use the keys temporarily. You will need to save it into your database or env files in order to keep it secured.

10. Your API key comes with a renewal date. Once it expires, all requests made using that key will be rejected. You can check the renewal date from the API Credentials section in the SKYBIZ Portal. To continue using the API after expiry, delete the expired credentials and create a new API key set.

11. To delete an API you can navigate to API Credentials Section > triple dot button > and click delete. It will delete your API Key and you are required to create new API Credentials Set to make any API Request.


Step 3 — View Module Permissions

1.Navigate to your newly added API Credentials set

2.Click the Modules Button at the right of the API Credentials set

3.The modal popup for Allowed Modules Permission for your store will be displayed. You can only make an API Request based on the modules allowed only. Contact your SKYBIZ Administrator for any changes.


Step 4 — Make your first API Read Request

Ensure your mode are set to developer mode to make a request using HTTP or postman. If you are set to production mode, you are required to make the request using HTTPS origins only. Also ensure your API Key Expiry Date is still valid.

All SKYBIZ API endpoints follow the same pattern:

  • Method: POST
  • Content-Type: application/json
  • Credentials: included in the request body (not in headers)

Base request structure:

{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "read",
"date_from": "YYYY-MM-DD",
"date_to": "YYYY-MM-DD",
"fields": [],
"filters": []
}

Date rules (applies to ALL modules):

  • Format must be YYYY-MM-DD — e.g. "2026-04-01"
  • Maximum range is 31 days
  • date_from cannot be after date_to

Sample Code for making an API READ request using php

<?php
header('Content-Type: application/json');

// ============================================================
// STEP 1: CONFIGURATION
// ============================================================

$API_KEY = "your-api-key";
$API_SECRET = "your-api-secret";
$ACTION = "read";

// Date range (required for all endpoints, max 31 days)
$DATE_FROM = "YYYY-MM-DD";
$DATE_TO = "YYYY-MM-DD";

// ============================================================
// STEP 2: ENDPOINT
// ============================================================

$BASE_URL = "https://domain-name/01/clientportal/apiv2/modules"; //(replace it with your skybiz domain name url)
$ENDPOINT = "modules.php"; //(replace it with your allowed modules permission e.g customer.php/supplier.php)

// ============================================================
// STEP 3: REQUEST PARAMETERS
// ============================================================

$requestParams = [
"date_from" => $DATE_FROM,
"date_to" => $DATE_TO,
"fields" => [], // Leave empty for all fields, or specify like: ["CusCode", "CusName", "Email"]
"filters" => [] // Optional filters, e.g.: ["Tel" => "0123456789"]
];

// ============================================================
// STEP 4: BUILD PAYLOAD
// ============================================================

$payload = array_merge(
[
"api_key" => $API_KEY,
"api_secret" => $API_SECRET,
"action" => $ACTION
],
$requestParams
);

// ============================================================
// STEP 5: SEND REQUEST
// ============================================================

$url = rtrim($BASE_URL, '/') . '/' . ltrim($ENDPOINT, '/');

$ch = curl_init($url);

curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($payload),
CURLOPT_TIMEOUT => 30,
]);

$response = curl_exec($ch);

// ============================================================
// STEP 6: HANDLE CURL ERROR
// ============================================================

if ($response === false) {
echo json_encode([
"status" => "error",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => curl_error($ch)
], JSON_PRETTY_PRINT);
curl_close($ch);
exit;
}

$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// ============================================================
// STEP 7: DECODE RESPONSE
// ============================================================

$result = json_decode($response, true);

if (!$result) {
echo json_encode([
"status" => "error",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => "Invalid JSON from API",
"raw_response" => $response
], JSON_PRETTY_PRINT);
exit;
}

// ============================================================
// STEP 8: RETURN CLEAN JSON FORMAT
// ============================================================

echo json_encode([
"status" => $result['status'] ?? "error",
"timestamp" => date("c"),
"request_id" => $result['request_id'] ?? uniqid("req_"),
"data" => $result['data'] ?? null,
"message" => $result['message'] ?? null
], JSON_PRETTY_PRINT);

Step for making an API READ request using postman

  1. Ensure method are set to POST when make a request
  2. Enter http://domain-name/01/clientportal/apiv2/modules/modules.php for the URL and replace it with your SKYBIZ domain name and allowed modules permission.
  3. Ensure all fields are correctly inserted in Raw-Body-JSON request.

 


Step 5 — Make your first API Create Request

A create request lets you push new documents into SKYBIZ. Unlike a read request, no date range is required — instead, you send a structured documents array containing your header and line item data.

Ensure your mode are set to developer mode to make a request using HTTP or postman. If you are set to production mode, you are required to make the request using HTTPS origins only. Also ensure your API Key Expiry Date is still valid.

All SKYBIZ API endpoints follow the same pattern:

  • Method: POST
  • Content-Type: application/json
  • Credentials: included in the request body (not in headers)
  • "action" must be set to "create"
  • You must have create permission enabled for the module (check via Step 3)

1. SALES (sales.php)

Request Key: sales_data

Allowed DocTypes: CusInv, CS, CusCN, CusDN

Compulsory Fields:

  • Header: Doc1No, CusCode, HCNetAmt, HCDtTax, DocType
  • Items: ItemCode, Description, Qty, FactorQty, UOM, HCUnitCost, HCLineAmt, BlankLine

Base Request Structure:

{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"sales_data": {
"documents": [
{
"Doc1No": "---",
"Doc2No": "---",
"Doc3No": "---",
"D_ate": "YYYY-MM-DD",
"CusCode": "---",
"HCNetAmt": 00.00,
"HCDtTax": 00.00,
"CurCode": "---",
"CurRate1": 1,
"DocType": "---",
"UD1": "---",
"items": [
{
"ItemCode": "---",
"Description": "---",
"Description2": "---",
"Qty": 1,
"FactorQty": 1,
"UOM": "---",
"HCUnitCost": 00.00,
"HCLineAmt": 00.00,
"HCDiscount": 0,
"DisRate1": 0,
"HCTax": 00.00,
"TaxRate1": 1,
"DetailTaxCode": "---",
"SalesPersonCode": "---",
"BranchCode": "--",
"DepartmentCode": "---",
"ProjectCode": "---",
"LocationCode": "---",
"BlankLine": "0",
"WarrantyDate": "YYYY-MM-DD",
"DUD1": "---",
"DUD2": "---",
"DUD3": "",
"DUD4": "",
"DUD5": "",
"DUD6": "",
"LineNo": 1
}
]
}
]
}
}

2. PURCHASE (purchase.php)

Request Key: purchase_data

Allowed DocTypes: SupInv, SupCN, SupDN

Compulsory Fields:

  • Header: Doc1No, CusCode, HCNetAmt, HCDtTax, DocType
  • Items: ItemCode, Description, Qty, FactorQty, UOM, HCUnitCost, HCLineAmt, BlankLine

Base Request Structure:

{
"api_key": "your-api-key-here",
"api_secret": "your-api-secret-here",
"action": "create",
"purchase_data": {
"documents": [
{
"Doc1No": "---",
"Doc2No": "---",
"Doc3No": "---",
"D_ate": "YYYY-MM-DD",
"CusCode": "---",
"HCNetAmt": 00.00,
"HCDtTax": 00.00,
"CurCode": "---",
"CurRate1": 1,
"DocType": "---",
"items": [
{
"ItemCode": "---",
"Description": "---",
"Description2": "---",
"Qty": 1,
"FactorQty": 1,
"UOM": "---",
"UOMSingular": "---",
"HCUnitCost": 00.00,
"HCLineAmt": 00.00,
"HCDiscount": 0,
"DisRate1": 0,
"HCTax": 00.00,
"TaxRate1": 1,
"DetailTaxCode": "---",
"BranchCode": "---",
"DepartmentCode": "---",
"ProjectCode": "---",
"LocationCode": "---",
"BlankLine": "0",
"WarrantyDate": "YYYY-MM-DD",
"GRNNo": "---",
"PORunNo": 1,
"PONO": "---",
"LandingCost": 0,
"OCCode": "",
"OCRate": 0,
"OCAmt": 0,
"GLCode": "---",
"FinCatCode": "---",
"DUD1": "---",
"DUD2": "---",
"LineNo": 1
},
{
"ItemCode": "---",
"Description": "---",
"Qty": 1,
"FactorQty": 1,
"UOM": "---",
"HCUnitCost": 00.00,
"HCLineAmt": 00.00,
"HCTax": 00.00,
"TaxRate1": 1,
"BlankLine": "0"
}
]
}
]
}
}

3. COLLECTION (collection.php)

Request Key: collection_data

Allowed DocTypes: CS, Collection, CF, CusCN

Compulsory Fields:

  • Doc1No, CusCode, D_ate, DocType
  • At least one payment method with amount > 0

Base Request Structure:

{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"collection_data": {
"documents": [
{
"Doc1No": "INV-001",
"CusCode": "CUST001",
"D_ate": "2026-05-12",
"T_ime": "14:30:00",
"DocType": "CS",
"T_ype": "CASH",
"CashAmt": 500.00,
"CC1Amt": 0,
"CC2Amt": 0,
"Cheque1Amt": 0,
"Cheque2Amt": 0,
"VoucherAmt": 0,
"Remark": "Payment for invoice"
}
]
}
}

4. CUSTOMER (customer.php)

Request Key: customer_data

Allowed DocTypes: N/A (not applicable for Customer)

Compulsory Fields:

  • AccountCode, CusCode, CusName, CurCode, D_ay, CategoryCode
  • FinCatCode is hardcoded as B55 (not required from user)

Base Request Structure:

{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"customer_data": {
"documents": [
{
"AccountCode": "AR-001",
"CusCode": "CUST001",
"CusName": "Customer Name",
"CurCode": "MYR",
"D_ay": 30,
"CategoryCode": "RETAIL",
"Address1": "123 Jalan SS2",
"Address2": "Section 2",
"AreaCode": "SEL",
"CreditLimit": 10000.00,
"SalesPersonCode": "SALES01",
"Tel": "03-12345678",
"Tel2": "012-3456789",
"Fax": "03-12345679",
"Fax2": "",
"Contact": "John Doe",
"ContactTel": "012-3456789",
"URL": "www.customer.com",
"Email": "customer@test.com",
"GSTNo": "123456789",
"Town": "Petaling Jaya",
"State": "Selangor",
"Country": "Malaysia",
"PostCode": "47300",
"NRICNo": "800101-01-1234",
"SalesTaxNo": "ST123456",
"TaxExemptionNo": "TX123456",
"TaxTel": "03-12345670",
"TaxEmail": "tax@customer.com"
}
]
}
}

5. SUPPLIER (supplier.php)

Request Key: supplier_data

Allowed DocTypes: N/A (not applicable for Supplier)

Compulsory Fields:

  • AccountCode, CusCode, CusName, CurCode, D_ay, CategoryCode
  • FinCatCode is hardcoded as B70 (not required from user)

Base Request Structure:

{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"supplier_data": {
"documents": [
{
"AccountCode": "AP-001",
"CusCode": "SUPP001",
"CusName": "Supplier Name",
"CurCode": "MYR",
"D_ay": 30,
"CategoryCode": "LOCAL",
"Address1": "123 Industrial Area",
"AreaCode": "SEL",
"CreditLimit": 100000.00,
"SalesPersonCode": "PURCHASE01",
"Tel": "03-12345678",
"Tel2": "012-3456789",
"Fax": "03-12345679",
"Fax2": "",
"Contact": "Ahmad Bin Abdullah",
"ContactTel": "012-3456789",
"URL": "www.supplier.com",
"Email": "supplier@test.com",
"GSTNo": "123456789",
"Town": "Shah Alam",
"State": "Selangor",
"Country": "Malaysia",
"PostCode": "40000",
"NRICNo": "750101-01-1234",
"SalesTaxNo": "ST123456",
"TaxExemptionNo": "TX123456",
"TaxTel": "03-12345670",
"TaxEmail": "tax@supplier.com"
}
]
}
}

6. SALES ORDER (sales_order.php)

Request Key: order_data

Allowed DocTypes: SO (Sales Order only)

Compulsory Fields:

  • Header: Doc1No, CusCode, HCNetAmt, HCDtTax, DocType
  • Items: ItemCode, Description, Qty, FactorQty, UOM, HCUnitCost, HCLineAmt, BlankLine

Base Request Structure:

{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"order_data": {
"documents": [
{
"Doc1No": "SO-001",
"Doc2No": "REF-001",
"Doc3No": "PO-001",
"D_ate": "2026-05-12",
"CusCode": "CUST001",
"CusName": "Customer Name",
"HCNetAmt": 1250.00,
"HCDtTax": 75.00,
"CurCode": "MYR",
"CurRate1": 1,
"DocType": "SO",
"Address": "123 Jalan SS2",
"City": "Petaling Jaya",
"State": "Selangor",
"Zip": "47300",
"ContactTel": "0123456789",
"Email": "customer@test.com",
"Attention": "Urgent order",
"items": [
{
"ItemCode": "ITEM001",
"Description": "Product 1",
"Description2": "Additional details",
"Qty": 10,
"FactorQty": 1,
"UOM": "PCS",
"UOMSingular": "Piece",
"HCUnitCost": 100.00,
"HCLineAmt": 1000.00,
"HCDiscount": 0,
"DisRate1": 0,
"HCTax": 8.00,
"TaxRate1": 8,
"DetailTaxCode": "TX001",
"SalesPersonCode": "SALES01",
"BranchCode": "HQ",
"DepartmentCode": "SALES",
"ProjectCode": "PROJ001",
"LocationCode": "WH01",
"BlankLine": "0",
"DeliveryDate": "2026-05-15",
"DUD1": "Batch#ABC123",
"DUD2": "Handle with care",
"LineNo": 1
}
]
}
]
}
}

BlankLine Values

Each item line requires a BlankLine value that tells SKYBIZ the type of line:

Value Type
"0" Stock Item
"4" Other Charge
"6" GL Account

⚠️ SKYBIZ validates that HCLineAmt = Qty × HCUnitCost and that the sum of all item HCLineAmt values matches the document header HCNetAmt. Mismatches will cause the entire document to fail.

Maximum Documents per Request

You can send up to 500 documents per create request. If you exceed this, split your data into multiple requests.

Sample Code for making an API CREATE request using php

<?php

header('Content-Type: application/json');

// ============================================================
// STEP 1: CONFIGURATION
// ============================================================

$API_KEY = "your-api-key";
$API_SECRET = "your-api-secret";
$ACTION = "create";

// ============================================================
// STEP 2: ENDPOINT
// ============================================================

$BASE_URL = "https://domain-name/01/clientportal/apiv2/modules"; // (replace with your SKYBIZ domain name url)
$ENDPOINT = "modules.php"; // (replace with your allowed module e.g. sales.php / purchase.php)

// ============================================================
// STEP 3: DATA KEY
//
// Set the data key that matches the module endpoint above.
// sales.php → "sales_data" (DocTypes: CusInv, CS, CusCN, CusDN)
// purchase.php → "purchase_data" (DocTypes: SupInv, SupCN, SupDN)
// ============================================================

$DATA_KEY = "sales_data"; // (replace with the data key that matches your endpoint above)

// ============================================================
// STEP 4: BUILD YOUR DOCUMENTS ARRAY
//
// Maximum: 500 documents per request.
// If you have more than 500, split them into multiple requests.
//
// COMPULSORY HEADER FIELDS (all modules):
// Doc1No, CusCode, DocType, HCNetAmt, HCDtTax
//
// COMPULSORY ITEM FIELDS (all modules):
// ItemCode, Description, Qty, FactorQty, UOM,
// HCUnitCost, HCLineAmt, BlankLine
//
// AMOUNT RULES (all modules):
// - HCLineAmt must equal Qty × HCUnitCost
// - HCTax must equal HCLineAmt × (TaxRate1 / 100)
// - Sum of all item HCLineAmt must equal document HCNetAmt
// - Sum of all item HCTax must equal document HCDtTax
//
// BLANKLINE VALUES:
// "0" = Stock Item | "4" = Other Charge | "6" = GL Account
//
// ============================================================
// SALES-SPECIFIC NOTES (sales.php):
// - CusCode = Customer Code
// - DocType = CusInv | CS | CusCN | CusDN
// - Date = Required. Defaults to today.
//
// PURCHASE-SPECIFIC NOTES (purchase.php):
// - CusCode = Supplier Code
// - DocType = SupInv | SupCN | SupDN 
// - D_ate = Document date. Format: YYYY-MM-DD. Defaults to today.
// - Doc2No = Optional. Supplier invoice reference number.
// - Doc3No = Optional. Additional reference.
// ============================================================

$DOCUMENTS = [];

// ============================================================
// OPTION A: MANUAL DOCUMENTS
// ============================================================

// --- SALES example ---
// $DOCUMENTS[] = [
// "Doc1No" => "INV-0001", // (required) Your invoice number
// "CusCode" => "C-000001", // (required) Customer code
// "DocType" => "CusInv", // (required) CusInv | CS | CusCN | CusDN
// "HCNetAmt" => 100.00, // (required) Must equal sum of all item HCLineAmt
// "HCDtTax" => 8.00, // (required) Must equal sum of all item HCTax
// "CurCode" => "MYR", // (optional) Default: MYR
// "CurRate1" => 1, // (optional) Default: 1
// "items" => [
// [
// "LineNo" => 1, // (optional) Auto-assigned if omitted
// "ItemCode" => "ITEM001", // (required) Must exist in SKYBIZ
// "Description" => "Product A", // (required)
// "Qty" => 2, // (required) Must be > 0
// "FactorQty" => 1, // (required) Default: 1. Must be > 0
// "UOM" => "PCS", // (required)
// "HCUnitCost" => 50.00, // (required) Must be > 0 for stock items
// "HCLineAmt" => 100.00, // (required) Must equal Qty × HCUnitCost
// "BlankLine" => "0", // (required) "0"=Stock, "4"=Other Charge, "6"=GL
// "HCTax" => 8.00, // (optional) Must equal HCLineAmt × TaxRate1%
// "TaxRate1" => 8, // (optional)
// "DetailTaxCode" => "GST8", // (optional) Must exist in SKYBIZ if provided
// "SalesPersonCode"=> "", // (optional) Must exist in SKYBIZ if provided
// "BranchCode" => "", // (optional) Must exist in SKYBIZ if provided
// "DepartmentCode" => "", // (optional) Must exist in SKYBIZ if provided
// "ProjectCode" => "", // (optional) Must exist in SKYBIZ if provided
// "LocationCode" => "", // (optional) Must exist in SKYBIZ if provided
// "WarrantyDate" => "", // Format: YYYY-MM-DD
// "Description2" => "", // (optional)
// "HCDiscount" => 0, // (optional)
// "DisRate1" => 0, // (optional)
// "DUD1" => "", // (optional) User-defined fields DUD1–DUD6
// "DUD2" => "",
// "DUD3" => "",
// "DUD4" => "",
// "DUD5" => "",
// "DUD6" => ""
// ]
// ]
// ];

// --- PURCHASE example ---
// $DOCUMENTS[] = [
// "Doc1No" => "PINV-0001", // (required) Your document number
// "CusCode" => "S-000001", // (required) Supplier code
// "DocType" => "SupInv", // (required) SupInv | SupCN | SupDN | PurRet
// "HCNetAmt" => 200.00, // (required) Must equal sum of all item HCLineAmt
// "HCDtTax" => 8.00, // (required) Must equal sum of all item HCTax
// "D_ate" => "2026-05-07", // Document date. Format: YYYY-MM-DD
// "Doc2No" => "PO-12345", // (optional) Supplier invoice reference
// "Doc3No" => "", // (optional) Additional reference
// "CurCode" => "MYR", // (optional) Default: MYR
// "CurRate1" => 1, // (optional) Default: 1. Must be > 0
// "items" => [
// [
// "LineNo" => 1, // (optional) Auto-assigned if omitted
// "ItemCode" => "ITEM001", // (required) Must exist in SKYBIZ
// "Description" => "Product B", // (required)
// "Qty" => 4, // (required) Must be > 0
// "FactorQty" => 1, // (required) Default: 1. Must be > 0
// "UOM" => "PCS", // (required)
// "HCUnitCost" => 50.00, // (required) Must be > 0 for stock items
// "HCLineAmt" => 200.00, // (required) Must equal Qty × HCUnitCost
// "BlankLine" => "0", // (required) "0"=Stock, "4"=Other Charge, "6"=GL
// "HCTax" => 8.00, // (optional) Must equal HCLineAmt × TaxRate1%
// "TaxRate1" => 8, // (optional)
// "DetailTaxCode" => "GST8", // (optional) Must exist in SKYBIZ if provided
// "BranchCode" => "", // (optional) Must exist in SKYBIZ if provided
// "DepartmentCode" => "", // (optional) Must exist in SKYBIZ if provided
// "ProjectCode" => "", // (optional) Must exist in SKYBIZ if provided
// "LocationCode" => "", // (optional) Must exist in SKYBIZ if provided
// "WarrantyDate" => "", // (optional) Format: YYYY-MM-DD
// "Description2" => "", // (optional)
// "UOMSingular" => "", // (optional) Singular form of UOM
// "GRNNo" => "", // (optional) GRN reference number
// "PORunNo" => 0, // (optional) PO run number
// "PONO" => "", // (optional) PO number
// "LandingCost" => 0, // (optional)
// "OCCode" => "", // (optional) Other charge code
// "OCRate" => 0, // (optional)
// "OCAmt" => 0, // (optional)
// "GLCode" => "", // (optional)
// "FinCatCode" => "", // (optional)
// "HCDiscount" => 0, // (optional)
// "DisRate1" => 0, // (optional)
// "DUD1" => "", // (optional) User-defined fields DUD1–DUD6
// "DUD2" => "",
// "DUD3" => "",
// "DUD4" => "",
// "DUD5" => "",
// "DUD6" => ""
// ]
// ]
// ];

// ============================================================
// OPTION B: READ FROM DATABASE (replace with your DB query)
// ============================================================

// $sql = "SELECT * FROM your_source_table LIMIT 500";
// $result = mysqli_query($your_conn, $sql);
// while ($row = mysqli_fetch_assoc($result)) {
// $DOCUMENTS[] = [
// "Doc1No" => $row['invoice_no'],
// "CusCode" => $row['customer_or_supplier_code'],
// "DocType" => $row['doc_type'],
// "HCNetAmt" => (float)$row['net_amount'],
// "HCDtTax" => (float)$row['tax_amount'],
// "CurCode" => "MYR",
// "CurRate1" => 1,
// "items" => json_decode($row['items'], true)
// ];
// }

// ============================================================
// OPTION C: READ FROM CSV FILE
// ============================================================

// if (($handle = fopen("your_data.csv", "r")) !== false) {
// $rowCount = 0;
// while (($data = fgetcsv($handle)) !== false && $rowCount < 500) {
// $DOCUMENTS[] = [
// "Doc1No" => $data[0],
// "CusCode" => $data[1],
// "DocType" => $data[2],
// "HCNetAmt" => (float)$data[3],
// "HCDtTax" => (float)$data[4],
// "CurCode" => "MYR",
// "CurRate1" => 1,
// "items" => [
// [
// "ItemCode" => $data[5],
// "Description" => $data[6],
// "Qty" => (float)$data[7],
// "FactorQty" => 1,
// "UOM" => "UNIT",
// "HCUnitCost" => (float)$data[8],
// "HCLineAmt" => (float)$data[9],
// "HCTax" => (float)$data[10],
// "TaxRate1" => 8,
// "BlankLine" => "0"
// ]
// ]
// ];
// $rowCount++;
// }
// fclose($handle);
// }

// ============================================================
// STEP 5: CLIENT-SIDE COUNT CHECK (PLease do not modify this)
// ============================================================

$totalDocuments = 0;

foreach ($DOCUMENTS as $document) {
$totalDocuments++;

if (empty($document['Doc1No'])) {
echo json_encode([
"status" => "REJECTED_BY_CLIENT",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => "CLIENT-SIDE REJECTION: Document at position {$totalDocuments} has empty Doc1No",
"action_required" => "Fix the document before sending to server"
], JSON_PRETTY_PRINT);
exit;
}
}

if ($totalDocuments > 500) {
echo json_encode([
"status" => "REJECTED_BY_CLIENT",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => "CLIENT-SIDE REJECTION: You have {$totalDocuments} documents. Maximum is 500.",
"your_document_count" => $totalDocuments,
"max_allowed" => 500,
"action_required" => "Reduce your documents to 500 or less BEFORE sending to server"
], JSON_PRETTY_PRINT);
exit;
}

echo "=== CLIENT-SIDE VALIDATION ===\n";
echo "Looped through all {$totalDocuments} documents one by one\n";
echo "All documents passed client validation\n";
echo "Document count: {$totalDocuments} (max 500)\n";
echo "Sending to server...\n\n";

// ============================================================
// STEP 6: SEND REQUEST
// ============================================================

$url = rtrim($BASE_URL, '/') . '/' . ltrim($ENDPOINT, '/');

$payload = [
"api_key" => $API_KEY,
"api_secret" => $API_SECRET,
"action" => $ACTION,
$DATA_KEY => ["documents" => $DOCUMENTS]
];

$ch = curl_init($url);

curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 120,
]);

$response = curl_exec($ch);

// ============================================================
// STEP 7: HANDLE CURL ERROR
// ============================================================

if ($response === false) {
echo json_encode([
"status" => "error",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => curl_error($ch)
], JSON_PRETTY_PRINT);
curl_close($ch);
exit;
}

$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// ============================================================
// STEP 8: DECODE RESPONSE
// ============================================================

$result = json_decode($response, true);

if (!$result) {
echo json_encode([
"status" => "error",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => "Invalid JSON from API",
"raw_response" => $response
], JSON_PRETTY_PRINT);
exit;
}

// ============================================================
// STEP 9: RETURN CLEAN JSON FORMAT
// ============================================================

echo "=== SERVER RESPONSE ===\n";
echo json_encode([
"status" => $result['status'] ?? "error",
"timestamp" => date("c"),
"request_id" => $result['request_id'] ?? uniqid("req_"),
"data" => $result['data'] ?? null,
"message" => $result['message'] ?? null
], JSON_PRETTY_PRINT);

Steps for Create Request Using Postman

  1. Ensure the method is set to POST
  2. Enter http://domain-name/01/clientportal/apiv2/modules/sales.php (or purchase.php) and replace with your SKYBIZ domain
  3. Under Body, select raw and set the format to JSON
  4. Paste your full payload including api_key, api_secret, action, and your sales_data or purchase_data

Step 6 — Read the Response

 

Every response from the API follows the same envelope structure:

Successful READ response in JSON Format:

{
"status": "success",
"timestamp": "2026-04-30T04:07:04+00:00",
"request_id": "req_69f2d56891e57",
"data": {
"requested_by": "4110a68b91ce2e2310fce51d3",
"mode": "2",
"date_range": {
"from": "2026-03-29",
"to": "2026-04-28",
"days": 31
},
"total_returned": 2,
"data": [
{
"CusCode": "C-000180",
"CusName": "TestAPI",
"Address": "",
"AreaCode": "",
"CurCode": "RM",
"Tel": "0123456789",
"Tel2": "",
"Fax": "",
"Fax2": "",
"Email": "test@gmail.com",
"Contact": "",
"ContactTel": "0123456789",
"Town": "Shah Alam",
"State": "Selangor",
"Country": "MALAYSIA",
"PostCode": "40470",
"SalesPersonCode": "",
"CreditLimit": 0,
"TermCode": 1,
"StatusBadYN": "0",
"DateStart": "2026-04-15",
"DOB": "0000-00-00",
"Sex": "Female",
"MemberType": "",
"DateTimeModified": "2026-04-09 11:29:47"
},

Successful READ response using Postman:

Error response:

{
"status": "error",
"timestamp": "2026-04-07T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Invalid API credentials"
}

Always check status first — if it is "error", read message to understand what went wrong.

Successful CREATE response in JSON Format:

{
"status": "success",
"timestamp": "2026-05-07T11:01:04+08:00",
"request_id": "req_69fc0070d83cf",
"data": {
"requested_by": "4110a68b91ce2e2310fce51d3",
"mode": "2",
"batch_id": "API20260507110104",
"summary": {
"total_documents": 1,
"inserted": 1,
"failed": 0
},
"successful_documents": [
"PURCHASE-TEST-001"
],
"failed_documents": [],
"fail_details": {
"compulsory_fields_missing": [],
"duplicate_documents": [],
"invalid_suppliers": [],
"invalid_items": [],
"invalid_tax_codes": [],
"invalid_locations": [],
"invalid_departments": [],
"invalid_projects": [],
"invalid_branches": [],
"amount_mismatch": [],
"validation_errors": []
}
}
}

Successful CREATE response using Postman:

Error response:

{
"status": "success",
"timestamp": "2026-05-07T11:15:48+08:00",
"request_id": "req_69fc03e446a20",
"data": {
"requested_by": "4110a68b91ce2e2310fce51d3",
"mode": "2",
"batch_id": "API20260507111548",
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"successful_documents": [],
"failed_documents": [
"PURCHASE-TEST-001"
],
"fail_details": {
"compulsory_fields_missing": [],
"duplicate_documents": [
"PURCHASE-TEST-001"
],
"invalid_suppliers": [],
"invalid_items": [],
"invalid_tax_codes": [],
"invalid_locations": [],
"invalid_departments": [],
"invalid_projects": [],
"invalid_branches": [],
"amount_mismatch": [],
"validation_errors": []
}
}
}

Always check summary.failed — if it is greater than 0, inspect fail_details and failed_documents to understand what went wrong before retrying.


Step 6 — Read Audit Logs

Every response from the API will submit an Audit Logs, you can view the audit logs in the SKYBIZ Portal > Active API Sessions.

Quick Reference — Common Errors

General (all requests)

Message What It Means Fix
"API key and secret are required" Missing credentials in body Add both api_key and api_secret to every request
"Invalid API credentials" Wrong key or secret Check your credentials. Re-register if needed
"Invalid API credentials: No expiry date set." API key has no renewal date configured Delete the credentials and create a new API key set
"API key expired on YYYY-MM-DD." API key has passed its renewal date Delete the expired credentials and create a new API key set
"API integration is disabled for this account" Mode is set to Disabled Ask your administrator to enable API Integration
"HTTPS is required for Production mode" Calling over plain HTTP Switch to HTTPS
"Rate limit exceeded" Too many requests Wait and retry with backoff

 

Read action only

Message What It Means Fix
"date_from and date_to are required" Missing date range Add both fields to every request
"Invalid date format. Use YYYY-MM-DD format." Wrong date format Use YYYY-MM-DD — e.g. "2026-04-01"
"Date range cannot exceed 31 days." Date range too wide Narrow range to 30 days or fewer
"No valid fields requested" No recognised field names Check field names against the Field Reference
"[Module] read permission denied" No read permission Enable permission in portal → Modules

Create action only

Message What It Means Fix
"sales_data is required for create action" Missing data payload Add sales_data or purchase_data to your request body
"sales_data.documents must be a non-empty array" Documents array is empty or wrong type Pass at least one document inside documents
"Maximum 500 documents allowed. You sent X." Too many documents Split into multiple requests of max 500 each
"[Module] create permission denied" No create permission Enable permission in portal → Modules
"Missing header fields - ..." Compulsory header fields not provided Include all required header fields
"Missing fields - ..." Compulsory item fields not provided Include all required item fields per line
"HCLineAmt does not match Qty × HCUnitCost" Amount calculation wrong Ensure HCLineAmt = Qty × HCUnitCost
"Header HCNetAmt does not match sum of HCLineAmt" Header total doesn’t add up Sum all item HCLineAmt and put the total in HCNetAmt
"Document already exists" Duplicate Doc1No Use a unique Doc1No
"ItemCode 'X' does not exist" Invalid item code Check the item code exists in SKYBIZ
"Customer/Supplier Code 'X' does not exist" Invalid customer or supplier code Check the code exists in SKYBIZ

Integration Mode Reference

Mode Name Where to Use HTTPS Required
0 Disabled
1 Production Live environment Yes
2 Developer Local development No (localhost only)

 

Need More Detail?

This guide covers the essentials to get you connected and making requests. For complete field references, full error documentation, and security guidelines, refer to the: SKYBIZ API Setup (Advanced)