SKYBIZ API — Sales Module
Sales
The Sales module allows you to retrieve and create sales invoice records in your SKYBIZ account. Supports both read and create operations.
Endpoint: /apiv2/modules/sales.php
Required Permissions: Sales — Read, Sales — Create
Allowed DocTypes: CusInv (Invoice), CS (Cash Sale), CusCN (Credit Note), CusDN (Debit Note)
Read Sales
Retrieves sales invoices created within the given date range. Returns all fields — no field filtering or custom filters are supported for this module.
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"
}
Request Parameters
| Parameter | Description | Required |
|---|---|---|
api_key |
Your API key | Yes |
api_secret |
Your API secret | Yes |
action |
Must be "read" |
Yes |
date_from |
Start date (YYYY-MM-DD) | Yes |
date_to |
End date (YYYY-MM-DD). Max 31 days range. | Yes |
Date Rules
- Format must be
YYYY-MM-DD— e.g."2026-04-01" - Maximum range is 31 days
date_fromcannot be afterdate_to
Available Fields (Read Only)
The Sales module returns all fields. Field filtering is not supported for this module.
| Field | Type | Description |
|---|---|---|
D_ate |
string | Invoice date |
Doc1No |
string | Primary document number (invoice number) |
Doc2No / Doc3No |
string | Secondary document reference numbers |
CusCode |
string | Customer code associated with the invoice |
DocType |
string | Document type — CusInv, CS, CusCN, or CusDN |
HCNetAmt |
float | Home currency net invoice amount |
HCDtTax |
float | Home currency detail tax total |
CurRate1 |
float | Currency exchange rate used on the invoice |
AdjAmt |
float | Adjustment amount applied to the invoice |
ItemCode |
string | Item code for the line item |
Description |
string | Line item description |
Qty |
float | Quantity sold |
FactorQty |
float | Factored quantity (adjusted for UOM conversion) |
UOM |
string | Unit of measure used on this line |
HCUnitCost |
float | Home currency unit cost on the line |
HCLineAmt |
float | Home currency line total amount |
HCDiscount |
float | Home currency discount amount on the line |
DisRate1 |
float | Discount rate applied to the line |
HCTax |
float | Home currency tax amount on the line |
TaxRate1 |
float | Tax rate applied to the line |
DetailTaxCode |
string | Tax code applied to the line item |
BlankLine |
string | Line type — "0" Stock Item, "4" Other Charge, "6" GL Account |
SalesPersonCode |
string | Salesperson code assigned to the line |
BranchCode |
string | Branch code associated with the line |
DepartmentCode |
string | Department code associated with the line |
ProjectCode |
string | Project code associated with the line |
LocationCode |
string | Stock location from which the item was sold |
WarrantyDate |
string | Warranty date for the line item |
ItemBatch |
string | Batch number of the item sold |
DUD1 to DUD6 |
string | User-defined fields 1 through 6 |
Example 1 — Get All Sales (All Fields)
This request returns all sales invoice fields for invoices created between April 1, 2026 and April 30, 2026.
Request
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "read",
"date_from": "2026-04-01",
"date_to": "2026-04-30"
}
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 = "2026-04-01";
$DATE_TO = "2026-04-30";
// ============================================================
// STEP 2: ENDPOINT
// ============================================================
$BASE_URL = "https://domain-name/01/clientportal/apiv2/modules"; //(replace it with your skybiz domain name url)
$ENDPOINT = "sales.php";
// ============================================================
// STEP 3: REQUEST PARAMETERS
// ============================================================
$requestParams = [
"date_from" => $DATE_FROM,
"date_to" => $DATE_TO
];
// ============================================================
// 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);
Response (Success)
{
"status": "response",
"timestamp": "2026-04-30T04:07:04+00:00",
"request_id": "req_69f2d56891e57",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"date_range": {
"from": "2026-04-01",
"to": "2026-04-30",
"days": 30
},
"total_returned": 2,
"data": [
{
"Doc1No": "INV-001",
"CusCode": "CUST001",
"DocType": "CusInv",
"HCNetAmt": 1500.00,
"HCDtTax": 120.00,
"D_ate": "2026-04-15",
"DateTimeModified": "2026-04-15 10:30:00"
},
{
"Doc1No": "INV-002",
"CusCode": "CUST002",
"DocType": "CusInv",
"HCNetAmt": 2500.00,
"HCDtTax": 200.00,
"D_ate": "2026-04-20",
"DateTimeModified": "2026-04-20 14:45:00"
}
]
}
}
Postman Steps — READ Request
- Set method to POST
2. Enter URL: https://your-domain/01/clientportal/apiv2/modules/sales.php
3. Set header: Content-Type: application/json
4. Under Body, select raw and format JSON
5. Paste your request payload and click Send
Create Sales Invoice
Creates one or more sales invoice records. All documents are validated before any are saved. If any document fails, the entire batch is rejected.
Compulsory Fields — Header
| Field | Type | Description |
|---|---|---|
Doc1No |
string | Unique document number. Must not already exist. |
CusCode |
string | Customer code. Must exist in SKYBIZ. |
DocType |
string | Document type — CusInv, CS, CusCN, or CusDN |
HCNetAmt |
float | Net amount before tax. Must equal sum of all item HCLineAmt. |
HCDtTax |
float | Total tax amount. Must equal sum of all item HCTax. |
Compulsory Fields — Items
| Field | Type | Description |
|---|---|---|
ItemCode |
string | Item code. Must exist in SKYBIZ (stock item, other charge, or GL account based on BlankLine). |
Description |
string | Item description (max 255 characters) |
Qty |
float | Quantity. Must be greater than 0 for stock items and other charges. |
FactorQty |
float | UOM conversion factor. Usually same as Qty. Must be greater than 0. |
UOM |
string | Unit of measure. Must exist in SKYBIZ UOM table. |
HCUnitCost |
float | Unit price. Must be greater than 0 for stock items. |
HCLineAmt |
float | Line total. Must equal Qty × HCUnitCost. |
BlankLine |
string | Line type — "0" Stock Item, "4" Other Charge, "6" GL Account |
Optional Fields — Header
| Field | Type | Description |
|---|---|---|
Doc2No / Doc3No |
string | Reference document numbers |
D_ate |
string | Document date in YYYY-MM-DD format. Defaults to today. |
CurCode |
string | Currency code. Default: MYR. Must exist in SKYBIZ if provided. |
CurRate1 |
float | Exchange rate. Default: 1. Must be greater than 0 if provided. |
Optional Fields — Items
| Field | Type | Description |
|---|---|---|
Description2 |
string | Second description line (max 255 characters) |
UOMSingular |
string | Singular form of UOM (auto-populated from UOM if empty) |
HCDiscount / DisRate1 |
float | Discount amount and discount rate (%) |
HCTax |
float | Tax amount for this line. Must equal HCLineAmt × (TaxRate1 / 100) if TaxRate1 > 0. |
TaxRate1 |
float | Tax rate in percent — e.g. 8. If provided, HCTax is validated. |
DetailTaxCode |
string | Tax code. If provided, must exist in SKYBIZ with TaxType ‘0’ or ‘1’. |
SalesPersonCode |
string | Salesperson code. If provided, must exist in SKYBIZ salesman table. |
BranchCode |
string | Branch code. If provided, must exist in SKYBIZ branch table. |
DepartmentCode |
string | Department code. If provided, must exist in SKYBIZ department table. |
ProjectCode |
string | Project code. If provided, must exist in SKYBIZ project table. |
LocationCode |
string | Stock location code. If provided, must exist in SKYBIZ location table. |
WarrantyDate |
string | Warranty date in YYYY-MM-DD format |
DUD1 to DUD6 |
string | User-defined detail fields 1 through 6 (max 40 characters each) |
LineNo |
integer | Line sequence number. Auto-assigned if omitted. |
BlankLine Values
| Value | Type | Description |
|---|---|---|
"0" |
Stock Item | Item code must exist. |
"4" |
Other Charge | Item code must exist. |
"6" |
GL Account | Item code must exist (GL account table). |
⚠️ Amount Validation Rules: 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.
Base Create Request Structure
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"sales_data": {
"documents": [
{
"Doc1No": "INV-001",
"CusCode": "CUST001",
"DocType": "CusInv",
"D_ate": "2026-05-20",
"HCNetAmt": 550.00,
"HCDtTax": 44.00,
"CurCode": "RM",
"CurRate1": 1,
"items": [
{
"ItemCode": "ITEM001",
"Description": "Product A",
"Qty": 10,
"FactorQty": 1,
"UOM": "Piece",
"HCUnitCost": 50.00,
"HCLineAmt": 500.00,
"BlankLine": "0",
"HCTax": 40.00,
"TaxRate1": 8,
"LineNo": 1
}
]
}
]
}
}
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 it with your skybiz domain name url)
$ENDPOINT = "sales.php";
// ============================================================
// STEP 3: DATA KEY
// ============================================================
$DATA_KEY = "sales_data";
// ============================================================
// STEP 4: BUILD YOUR DOCUMENTS ARRAY
// ============================================================
$DOCUMENTS = [];
// --- Sales example ---
$DOCUMENTS[] = [
"Doc1No" => "INV-001",
"CusCode" => "CUST001",
"DocType" => "CusInv",
"D_ate" => "2026-05-20",
"HCNetAmt" => 550.00,
"HCDtTax" => 44.00,
"CurCode" => "RM",
"CurRate1" => 1,
"items" => [
[
"ItemCode" => "ITEM001",
"Description" => "Product A",
"Qty" => 10,
"FactorQty" => 1,
"UOM" => "Piece",
"HCUnitCost" => 50.00,
"HCLineAmt" => 500.00,
"BlankLine" => "0",
"HCTax" => 40.00,
"TaxRate1" => 8,
"LineNo" => 1
]
]
];
// ============================================================
// 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);
Response (Success)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_69fc0070d83cf",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"summary": {
"total_documents": 1,
"inserted": 1,
"failed": 0
},
"successful_documents": ["INV-001"],
"failed_documents": [],
"fail_details": {
"compulsory_fields_missing": [],
"duplicate_documents": [],
"invalid_customers": [],
"invalid_items": [],
"invalid_tax_codes": [],
"invalid_sales_persons": [],
"invalid_locations": [],
"invalid_departments": [],
"invalid_projects": [],
"invalid_branches": [],
"invalid_currencies": [],
"invalid_uoms": [],
"amount_mismatch": [],
"validation_errors": []
}
}
}
Response (Error — Duplicate Document)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_69fc03e446a20",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"successful_documents": [],
"failed_documents": ["INV-001"],
"fail_details": {
"duplicate_documents": ["INV-001"],
"invalid_currencies": [],
"invalid_uoms": [],
"amount_mismatch": [],
"validation_errors": {}
}
}
}
Error Responses
Missing Date Range (READ)
{
"status": "error",
"timestamp": "2026-04-07T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "date_from and date_to are required"
}
Invalid Date Format
{
"status": "error",
"timestamp": "2026-04-07T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Invalid date format. Use YYYY-MM-DD format."
}
Date Range Exceeds 31 Days
{
"status": "error",
"timestamp": "2026-04-07T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Date range cannot exceed 31 days."
}
Invalid DocType (CREATE)
{
"status": "error",
"timestamp": "2026-04-07T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Invalid DocType 'XXX'. Allowed: CusInv, CS, CusCN, CusDN"
}
Missing Compulsory Fields (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"compulsory_fields_missing": [
"Document 1 (Doc1No: INV-001): Missing header fields - CusCode, HCNetAmt, HCDtTax, DocType"
]
}
}
}
Invalid Customer Code (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"invalid_customers": [
{
"customer_code": "INVALID",
"document_no": "INV-001",
"error": "Customer Code 'INVALID' does not exist"
}
]
}
}
}
Invalid Item Code (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"invalid_items": [
{
"item_code": "INVALID",
"document_no": "INV-001",
"line_no": 1,
"blank_line_type": "0 (Stock Item)"
}
]
}
}
}
Invalid UOM Code (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"invalid_uoms": [
{
"uom_code": "INVALID",
"document_no": "INV-001",
"line_no": 1,
"error": "UOM code 'INVALID' does not exist"
}
]
}
}
}
Invalid Currency Code (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"invalid_currencies": [
"Document 1 (Doc1No: INV-001): Currency code 'INVALID' does not exist"
]
}
}
}
Amount Mismatch — Line Level (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"amount_mismatch": {
"INV-001": [
{
"line_no": 1,
"item_code": "ITEM001",
"provided_hclineamt": "100.00",
"expected_hclineamt": "500.00",
"error": "HCLineAmt does not match Qty × HCUnitCost"
}
]
}
}
}
}
Amount Mismatch — Header Level (CREATE)
{
"status": "response",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"data": {
"summary": {
"total_documents": 1,
"inserted": 0,
"failed": 1
},
"failed_documents": ["INV-001"],
"fail_details": {
"amount_mismatch": {
"INV-001": [
"Header HCNetAmt (100.00) does not match sum of HCLineAmt (500.00)"
]
}
}
}
}
No Read Permission
{
"status": "error",
"timestamp": "2026-04-07T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Sales read permission denied"
}
No Create Permission
{
"status": "error",
"timestamp": "2026-05-20T10:30:00+08:00",
"request_id": "req_123456",
"message": "Sales create permission denied"
}
Common Errors — Sales Module
| Error Message | Cause | Fix |
|---|---|---|
"date_from and date_to are required" |
Missing date range (READ only) | Add both fields to your 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 31 days or fewer |
"Invalid DocType 'XXX'. Allowed: CusInv, CS, CusCN, CusDN" |
Wrong DocType in CREATE request | Use one of the allowed DocTypes |
"Missing fields - ItemCode, Description, Qty, FactorQty, UOM, HCUnitCost, HCLineAmt, BlankLine" |
Compulsory item fields not provided (CREATE) | Include all required fields for each item |
"UOM code 'X' does not exist" |
Invalid Unit of Measure (CREATE) | Check the UOM exists in SKYBIZ (singular or plural form) |
"Currency code 'X' does not exist" |
Invalid currency code (CREATE) | Use a valid currency code (e.g., RM, SGD, USD) |
"Customer Code 'X' does not exist" |
Invalid customer code | Check the customer code exists in SKYBIZ |
"ItemCode 'X' does not exist" |
Invalid item code | Check the item code exists in SKYBIZ (stock item, other charge, or GL account based on BlankLine) |
"HCLineAmt does not match Qty × HCUnitCost" |
Amount calculation mismatch (CREATE) | Ensure HCLineAmt = Qty × HCUnitCost (tolerance: ±0.01) |
"Header HCNetAmt does not match sum of HCLineAmt" |
Header total doesn’t match item totals (CREATE) | Set HCNetAmt to the sum of all item HCLineAmt (tolerance: ±0.01) |
"HCTax does not match HCLineAmt × TaxRate1%" |
Tax calculation mismatch (CREATE) | Ensure HCTax = HCLineAmt × (TaxRate1 / 100) (tolerance: ±0.01) when TaxRate1 > 0 |
"Document already exists" |
Duplicate Doc1No (CREATE) |
Use a unique Doc1No for each document |
"Qty must be greater than 0 for Stock Item" |
Quantity is zero or negative for stock item (CREATE) | Set Qty to a positive number greater than 0 |
"HCUnitCost must be greater than 0 for stock items" |
Unit cost is zero or negative for stock item (CREATE) | Set HCUnitCost to a positive number greater than 0 |
"FactorQty must be greater than 0" |
Factor quantity is zero or negative (CREATE) | Set FactorQty to a positive number (default is 1) |
"Sales read permission denied" |
No read permission for Sales module | Enable read permission in portal by contacting your SkyBiz Admin |




