SKYBIZ API — TMS Module
TMS Brand
The TMS Brand module allows you to retrieve, create, update, and delete brand records in your SKYBIZ TMS master data. Supports read, create, update, and delete operations.
Endpoint: /apiv2/modules/tms_brand.php
Required Permissions: TMS Brand — Read, TMS Brand — Create, TMS Brand — Update, TMS Brand — Delete (as applicable to the action used)
Primary Key: Code — unique per brand, and fixed once created (cannot be changed via update).
Batch Limit: Maximum 500 documents per request for create, update, and delete.
Data Wrapper Key: Documents for this module are wrapped under brand_data.
Allowed Fields
This are the field name that sent in a create or update request.
| Field | Type | Description |
|---|---|---|
Code |
string | Unique brand code. Primary key. Required for every action. Fixed — cannot be changed once created |
Name |
string | Brand name |
Read TMS Brand
Retrieves brand records. No date range is required for this module. You may optionally select specific fields and/or filter by exact field values.
Base Request Structure
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "read",
"fields": ["Code", "Name"],
"filters": {
"Code": "BR001"
}
}
Request Parameters
| Parameter | Description | Required |
|---|---|---|
api_key |
Your API key | Yes |
api_secret |
Your API secret | Yes |
action |
Must be "read" |
Yes |
fields |
Array of field names to return (Code and/or Name). Any other name is silently dropped. Omit or leave empty to return both fields |
No |
filters |
Object of field: value pairs. Each is applied as an exact-match (=) condition, combined with AND. Only Code and Name are recognized; other keys are ignored |
No |
Read Rules
- Results are ordered by
Code - No date range parameter exists or is required for this module
- No pagination — all matching rows are returned in a single response
- Filters are exact-match only (no partial/LIKE matching, no operators)
- If
fieldsis provided but none of the values match an allowed field, the request is rejected with"No valid fields requested"
Example 1 — Get All Brands
Request
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "read"
}
Example 2 — Look Up a Single Code
Request
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "read",
"filters": {
"Code": "BR001"
}
}
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";
// ============================================================
// STEP 2: ENDPOINT
// ============================================================
$BASE_URL = "https://domain-name/01/clientportal/apiv2/modules"; //(replace it with your skybiz domain name url)
$ENDPOINT = "tms_brand.php";
// ============================================================
// STEP 3: REQUEST PARAMETERS (both optional)
// ============================================================
$FIELDS = ["Code", "Name"];
$FILTERS = [
"Code" => "BR001"
];
// ============================================================
// STEP 4: BUILD PAYLOAD
// ============================================================
$payload = [
"api_key" => $API_KEY,
"api_secret" => $API_SECRET,
"action" => $ACTION,
"fields" => $FIELDS,
"filters" => $FILTERS
];
// ============================================================
// 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 => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
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;
}
curl_close($ch);
$result = json_decode($response, true);
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-09-25T04:07:04+00:00",
"request_id": "req_69f2d56891e57",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"total_returned": 1,
"data": [
{
"Code": "BR001",
"Name": "Acme Apparel"
}
]
}
}
Create TMS Brand
Creates one or more brand records. All documents are validated before any are saved. If any document fails validation, the entire batch is rejected — nothing is inserted.
Field Rules
| Field | Type | Rule |
|---|---|---|
Code |
string | Compulsory. Must not be empty. Must not already exist — checked both within the request batch and against existing records |
Name |
string | Optional. Blank/empty if not provided |
⚠️ Duplicate Check Order: The batch is first checked for duplicate Code values within the same request, then checked against existing records in SKYBIZ. Either kind of duplicate fails the entire batch, not just the duplicate document.
Base Create Request Structure
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "create",
"brand_data": {
"documents": [
{
"Code": "BR001",
"Name": "Acme Apparel"
}
]
}
}
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 = "tms_brand.php";
// ============================================================
// STEP 3: DATA KEY
// ============================================================
$DATA_KEY = "brand_data";
// ============================================================
// STEP 4: BUILD YOUR DOCUMENTS ARRAY
// ============================================================
$DOCUMENTS = [];
$DOCUMENTS[] = [
"Code" => "BR001",
"Name" => "Acme Apparel"
];
// ============================================================
// STEP 5: CLIENT-SIDE COUNT CHECK (Please do not modify this)
// ============================================================
$totalDocuments = 0;
foreach ($DOCUMENTS as $document) {
$totalDocuments++;
if (empty($document['Code'])) {
echo json_encode([
"status" => "REJECTED_BY_CLIENT",
"timestamp" => date("c"),
"request_id" => uniqid("req_"),
"message" => "CLIENT-SIDE REJECTION: Document at position {$totalDocuments} has empty Code",
"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 "Sending {$totalDocuments} document(s) 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);
curl_close($ch);
$result = json_decode($response, true);
echo "=== SERVER RESPONSE ===\n";
echo json_encode($result, JSON_PRETTY_PRINT);
Response (Success)
{
"status": "response",
"timestamp": "2026-09-25T10: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": ["BR001"],
"failed_documents": [],
"fail_details": {
"duplicate_in_request": [],
"duplicate_brands": [],
"validation_errors": []
}
}
}
Response (Error — Duplicate Brand)
{
"status": "response",
"timestamp": "2026-09-25T10: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": ["BR001"],
"fail_details": {
"duplicate_in_request": [],
"duplicate_brands": [
{
"code": "BR001",
"error": "Brand code already exists"
}
],
"validation_errors": []
}
}
}
Update TMS Brand
Updates one or more existing brand records, matched by Code. Since Name is the only updatable field, an update document is effectively just Code plus a new Name. All documents are pre-validated before anything is written; if any document in the batch fails, the entire batch is rejected.
Field Rules
| Field | Rule |
|---|---|
Code |
Compulsory in every document — used to look up the record. Fixed — including it only identifies the row, it is never itself updated |
Name |
Must be present — it’s the only other Allowed Field, and at least one field besides Code is required |
| Any field not in the Allowed Fields list | Not permitted — fails the whole batch |
Pre-flight Validation (checked before any write, whole batch fails together)
- Every document must have a non-empty
Code - No duplicate
Codewithin the same request batch - No unrecognized field names (anything outside
Code/Name) - Every document must include
Name— sending onlyCodeis rejected as “nothing to update” - Every
Codemust already exist in SKYBIZ — if even one is not found, the whole batch is rejected
⚠️ All-or-Nothing: A single bad document (not found, duplicate, unknown field, or nothing to update) causes every document in the request — including the valid ones — to fail.
Base Update Request Structure
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "update",
"brand_data": {
"documents": [
{
"Code": "BR001",
"Name": "Acme Apparel Co."
}
]
}
}
Sample Code for making an API UPDATE request using php
<?php
header('Content-Type: application/json');
$API_KEY = "your-api-key";
$API_SECRET = "your-api-secret";
$ACTION = "update";
$BASE_URL = "https://domain-name/01/clientportal/apiv2/modules"; //(replace it with your skybiz domain name url)
$ENDPOINT = "tms_brand.php";
$DOCUMENTS = [];
$DOCUMENTS[] = [
"Code" => "BR001",
"Name" => "Acme Apparel Co."
];
if (count($DOCUMENTS) > 500) {
echo json_encode([
"status" => "REJECTED_BY_CLIENT",
"message" => "Maximum 500 documents per request."
], JSON_PRETTY_PRINT);
exit;
}
$url = rtrim($BASE_URL, '/') . '/' . ltrim($ENDPOINT, '/');
$payload = [
"api_key" => $API_KEY,
"api_secret" => $API_SECRET,
"action" => $ACTION,
"brand_data" => ["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);
curl_close($ch);
echo json_encode(json_decode($response, true), JSON_PRETTY_PRINT);
Response (Success)
{
"status": "response",
"timestamp": "2026-09-25T11:00:00+08:00",
"request_id": "req_69fc1234abcd",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"summary": {
"total_documents": 1,
"updated": 1,
"not_found": 0,
"failed": 0
},
"successful_documents": ["BR001"],
"not_found_documents": [],
"failed_documents": [],
"fail_details": {
"not_found": [],
"nothing_to_update": [],
"unknown_fields": [],
"validation_errors": []
}
}
}
Response (Error — Brand Not Found)
{
"status": "response",
"timestamp": "2026-09-25T11:00:00+08:00",
"request_id": "req_69fc5678efgh",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"summary": {
"total_documents": 1,
"updated": 0,
"not_found": 1,
"failed": 1
},
"successful_documents": [],
"not_found_documents": ["BR999"],
"failed_documents": ["BR999"],
"fail_details": {
"not_found": ["BR999"],
"nothing_to_update": [],
"unknown_fields": [],
"validation_errors": []
}
}
}
Response (Error — Unknown Field)
{
"status": "response",
"data": {
"summary": { "total_documents": 1, "updated": 0, "not_found": 0, "failed": 1 },
"successful_documents": [],
"not_found_documents": [],
"failed_documents": ["BR001"],
"fail_details": {
"not_found": [],
"nothing_to_update": [],
"unknown_fields": {
"BR001": ["Description"]
},
"validation_errors": []
}
}
}
Delete TMS Brand
Deletes one or more brand records, matched by Code. This permanently removes the record — there is no undo. All documents are pre-validated before anything is deleted; if any document fails, the entire batch is rejected.
Pre-flight Validation (checked before any write, whole batch fails together)
- Every document must have a non-empty
Code - No duplicate
Codewithin the same request batch - Every
Codemust already exist in SKYBIZ — if even one is not found, the whole batch is rejected and nothing is deleted
Base Delete Request Structure
{
"api_key": "your-api-key",
"api_secret": "your-api-secret",
"action": "delete",
"brand_data": {
"documents": [
{ "Code": "BR001" },
{ "Code": "BR002" }
]
}
}
Sample Code for making an API DELETE request using php
<?php
header('Content-Type: application/json');
$API_KEY = "your-api-key";
$API_SECRET = "your-api-secret";
$ACTION = "delete";
$BASE_URL = "https://domain-name/01/clientportal/apiv2/modules"; //(replace it with your skybiz domain name url)
$ENDPOINT = "tms_brand.php";
$DOCUMENTS = [
["Code" => "BR001"],
["Code" => "BR002"]
];
if (count($DOCUMENTS) > 500) {
echo json_encode([
"status" => "REJECTED_BY_CLIENT",
"message" => "Maximum 500 documents per request."
], JSON_PRETTY_PRINT);
exit;
}
$url = rtrim($BASE_URL, '/') . '/' . ltrim($ENDPOINT, '/');
$payload = [
"api_key" => $API_KEY,
"api_secret" => $API_SECRET,
"action" => $ACTION,
"brand_data" => ["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);
curl_close($ch);
echo json_encode(json_decode($response, true), JSON_PRETTY_PRINT);
Response (Success)
{
"status": "response",
"timestamp": "2026-09-25T11:15:00+08:00",
"request_id": "req_69fc9999ijkl",
"data": {
"requested_by": "your-api-key",
"mode": "2",
"summary": {
"total_documents": 2,
"deleted": 2,
"not_found": 0,
"failed": 0
},
"successful_documents": ["BR001", "BR002"],
"not_found_documents": [],
"failed_documents": [],
"fail_details": {
"not_found": [],
"validation_errors": []
}
}
}
Response (Error — Brand Not Found)
{
"status": "response",
"data": {
"summary": { "total_documents": 1, "deleted": 0, "not_found": 1, "failed": 1 },
"successful_documents": [],
"not_found_documents": ["BR999"],
"failed_documents": ["BR999"],
"fail_details": {
"not_found": ["BR999"],
"validation_errors": []
}
}
}
Rate Limits & Quota
- Rate limit: 5 requests per 10 seconds, enforced per IP address and per API key. Exceeding it returns HTTP 429 with
"Rate limit exceeded" - Monthly quota: checked only on
create, against the record count already used this month for TMS Brand.read,update, anddeleteare not quota-limited - Batch cap: 500 documents per request for
create,update, anddelete(not applicable toread)
Error Responses
Missing API Credentials
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "API key and secret are required"
}
Invalid API Credentials
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Invalid API credentials"
}
Expired API Key
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "API key expired on 2026-08-01. Please delete the expired credentials and create a new API key set to continue using the API."
}
Missing / Invalid Action
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "action is required. Use 'read', 'create', 'update', or 'delete'"
}
No Permission for Action
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "tms_brand update permission denied"
}
Missing brand_data / documents (CREATE / UPDATE / DELETE)
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "brand_data.documents must be a non-empty array"
}
Batch Limit Exceeded (CREATE / UPDATE / DELETE)
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Maximum 500 documents allowed. You sent 600. Please split into multiple requests with max 500 documents each."
}
Monthly Quota Exceeded (CREATE only)
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "Quota exceeded! You have used 950 out of 1000 records this month. You requested 100 more records, but only 50 remaining. Please reduce your request or contact administrator to increase quota."
}
Rate Limit Exceeded
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"data": {
"key": "your-api-key",
"limit": 5,
"window_seconds": 10
},
"message": "Rate limit exceeded"
}
No Valid Fields Requested (READ)
{
"status": "error",
"timestamp": "2026-09-25T10:46:15+08:00",
"request_id": "req_6612f3b9c21a7",
"message": "No valid fields requested"
}
Common Errors — TMS Brand Module
| Error Message | Cause | Fix |
|---|---|---|
"API key and secret are required" |
Missing api_key or api_secret |
Include both in the request |
"Invalid action. Use 'read', 'create', 'update', or 'delete'" |
Unsupported action value |
Use one of the four supported actions |
"brand_data is required for create action" (or update/delete) |
Missing brand_data object |
Wrap your documents in brand_data.documents |
"Maximum 500 documents allowed..." |
More than 500 documents in one create/update/delete request | Split into batches of 500 or fewer |
"Document with empty Code found in batch" |
A document is missing Code (CREATE) |
Every document needs a non-empty Code |
"Duplicate Code 'X' found in the same batch" |
Same Code sent twice in one request |
Remove the duplicate, or send it in a separate request |
"Brand code already exists" |
Code already exists in SKYBIZ (CREATE) |
Use a unique Code, or use update instead |
Code listed under not_found_documents |
Code does not exist in SKYBIZ (UPDATE / DELETE) |
Check the code exists, or use create first |
Field name listed under unknown_fields |
A field other than Code/Name was sent (UPDATE) |
Only Code and Name are recognized — remove anything else |
"No updatable fields provided (only PK was sent)" |
Document contained only Code, no Name (UPDATE) |
Include Name — it’s the only field there is to update |
"No valid fields requested" |
fields array contains no recognized field names (READ) |
Use Code and/or Name |
"tms_brand read/create/update/delete permission denied" |
API key’s module permissions don’t include that action | Enable the permission in the portal by contacting your SkyBiz Admin |
"Rate limit exceeded" |
More than 5 requests in a 10-second window | Slow down request frequency / add retry backoff |
"Quota exceeded!..." |
Monthly record quota reached (CREATE only) | Reduce batch size or contact administrator to raise quota |