This technical manual is organized sequentially into the following eleven architectural sections:
| Section |
Section Title |
Target Endpoint / Scope |
Specification Summary |
| 1.0 |
API Overview |
System Architecture |
Core capabilities, non-destructive UPSERT, idempotency, company auth, optional counter scoping |
| 2.0 |
Base URL & Authentication |
Gateway Architecture |
Production base URL, Company-scoped JWT security architecture, tenant isolation |
| 2.1 |
Login API |
POST /Login |
Third-party service credential exchange and Company-scoped Bearer JWT generation |
| 2.2 |
Outlet List API |
POST /GetOutlets |
Query active enterprise showroom outlets under authenticated company |
| 3.0 |
Counter Management |
Showroom Counter Subsystem |
Native third-party counter APIs, store topology, optional counter scoping |
| 3.1 |
Add Counter API |
POST /AddCounter |
Creation of showroom display counters under authorized outlet |
| 3.2 |
Counter List API |
POST /GetCounters |
Querying active outlet display counters (alias /GetOutletCounter) |
| 3.3 |
Counter_Id Usage & Optionality |
Operational Stock Pipeline |
Dual stock pipeline: With Counter (counter-wise) vs No Counter (outlet-wise) |
| 4.0 |
UploadStock |
POST /UploadStock |
Production jewellery inventory upload with Outlet_Id, optional Counter_Id, and idempotency |
| 5.0 |
StockOperation |
POST /StockOperation |
Granular stock lifecycle operations (SET, ADD, UPDATE, REMOVE) |
| 6.0 |
ResetStock |
POST /ResetStock |
Soft-deactivation of active stock for an outlet and optional counter |
| 7.0 |
Session Summary |
POST /Reports/SessionSummary |
Audit reporting for batch upload history, insertion totals, and error metrics |
| 8.0 |
Stock Count |
POST /Reports/StockCount |
Real-time count of active showroom jewellery items grouped by counter or outlet |
| 9.0 |
Integration Flow |
7-Step Production Lifecycle |
End-to-end POS/ERP integration: Login → GetOutlets → Select Outlet → Stock Operations |
| 10.0 |
Error Handling |
Diagnostics Matrix |
Consolidated HTTP statuses, tenant rejections, and diagnostics |
| 11.0 |
API Logging & Verification |
rest_perfecto_service_audit_logs |
Automated audit logging middleware and backend verified test matrix |
The Perfecto Jewellery Third-Party REST API is a dedicated, production-grade integration service built natively into the Perfecto ERP platform (perfecto-api). It enables Point-of-Sale (POS) systems, custom billing software, enterprise warehouse platforms, and third-party ERP vendors to synchronize jewellery showroom inventory with Perfecto ERP in real time via structured HTTP REST requests.
Core Architectural Guarantees
- Direct System-to-System REST API: Synchronizes stock directly via HTTP POST requests without Excel spreadsheets, CSV parsing, or manual human imports.
- Non-Destructive UPSERT Engine: Uploading new jewellery items or modifying item attributes does NOT delete, wipe, or deactivate unmentioned active showroom stock. Stock remains live until explicitly updated or soft-deactivated.
- Flexible Showroom Counter Scoping: Showroom merchandise in Perfecto ERP can be tracked at the showroom level or allocated to specific display counters (
mst_counter_stock). Counter_Id is optional: With Counter_Id → counter-wise stock; Without Counter_Id → outlet-wise stock like before.
- Built-in Idempotency Protection: Every batch upload supports a client-generated
Reference_Id. Submitting identical Reference_Id values returns the cached response, preventing accidental duplicate inventory on network retries.
- Strict Multi-Tenant Company & Outlet Isolation: API credentials in
rest_perfecto_service_credentials authenticate at the Company level. A single company token operates across all showrooms belonging to that company. Cross-company access is strictly blocked.
- Standard JSON Payload Architecture: All payloads and responses strictly utilize pure
application/json. Multipart form-data or encrypted wrapper bodies are unnecessary for third-party operations.
All third-party integration requests must target the verified production gateway. Localhost and developer LAN endpoints must NOT be hardcoded into third-party software.
Authentication & Security Architecture
RestPerfectoService enforces an isolated, enterprise-grade authentication pipeline:
- Isolated Credential Repository: API credentials (Username, Password_Hash, Company_Id, Is_Active) are provisioned by Store Administrators and stored in
rest_perfecto_service_credentials at Company level.
- Cryptographic Password Protection: Passwords are protected using 10,000 rounds of PBKDF2 with HMAC-SHA512 and cryptographic per-user salt.
- Stateless Access Tokens: Calling
POST /Login returns a cryptographically signed HMAC-SHA256 JSON Web Token (JWT) with a 24-hour TTL. The token is Company-scoped and valid across all authorized company showrooms.
- Mandatory Bearer Authorization: All protected endpoints require the HTTP Authorization header:
Authorization: Bearer <ACCESS_TOKEN>.
- Real-Time Revocation Enforcement: On every protected API request, middleware checks the database to confirm
Is_Active = 1. If an administrator deactivates the credential, active tokens are revoked immediately with HTTP 401.
Authenticates third-party service credentials and issues a 1-hour JWT Bearer Access Token.
| Attribute |
Implementation Detail |
| Purpose |
Exchange third-party service credentials for a 1-hour Bearer JWT access token |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/Login |
| Authentication |
None (Public Entrypoint) |
| Headers |
Content-Type: application/json |
Request Parameters
| Field Name |
Type |
Required |
Description |
Example |
Username |
String |
Yes |
Service username allocated in Admin Portal |
"surat_jewellers_pos" |
Password |
String |
Yes |
Service password allocated in Admin Portal |
"XXXXXXXXXXXXXXXXXX" |
Example: POST /Login Request Payload
POST /api/v1/RestPerfectoService/Login
Content-Type: application/json
{
"Username": "surat_jewellers_pos",
"Password": "XXXXXXXXXXXXXXXXXX"
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Login successful.",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjcmVkZW50aWFsSWQiOjEsImNvbXBhbnlJZCI6MSwidXNlcm5hbWUiOiJzdXJhdF9qZXdlbGxlcnNfcG9zIiwidG9rZW5UeXBlIjoiUmVzdFBlcmZlY3RvU2VydmljZSIsImp0aSI6IjgxZjQyZGEzLTExOGItNDRhOC1iMTYxLTU5MDZhMmFlMzM1OCIsImlhdCI6MTc3NDYwMDAwMCwiZXhwIjoxNzc0Njg2NDAwfQ.s...",
"expires_in": 86400,
"token_type": "Bearer",
"company": {
"Company_Id": 1,
"Company_Name": "Surat Jewellers Enterprise"
}
}
}
Response Fields Description
| JSON Field |
Type |
Description |
status |
String |
"1" on successful authentication; "0" on error |
message |
String |
Human-readable status summary ("Login successful.") |
data.token |
String |
Signed Company-scoped JWT Bearer token valid across all company outlets |
data.Token_Type |
String |
Token scheme name ("Bearer") |
data.expires_in |
Number |
Token validity lifetime in seconds (86400 = 24 hours) |
Error Responses (HTTP 200 / 401)
// Scenario 1: Invalid Credentials
{
"status": "0",
"message": "Invalid username or password.",
"token": "",
"data": {}
}
// Scenario 2: Inactive Service Account (Is_Active = 0)
{
"status": "0",
"message": "RestPerfectoService access is inactive.",
"token": "",
"data": {}
}
// Scenario 3: Missing Fields
{
"status": "0",
"message": "Username and Password are required.",
"token": "",
"data": {}
}
Active outlets of the authenticated company can be retrieved for selecting the target Outlet_Id. External POS, billing, and ERP synchronization systems must query this endpoint to obtain the authorized Outlet_Id values belonging to their enterprise before executing stock uploads or operations.
| Attribute |
Implementation Detail |
| Purpose |
Active outlets of the authenticated company can be retrieved for selecting the target Outlet_Id |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/GetOutlets |
| Backward-Compatible Alias |
POST /api/v1/RestPerfectoService/GetOutlet |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <ACCESS_TOKEN> |
Request Parameters
| Field Name |
Type |
Required |
Description |
Outlet_Id |
Integer |
Optional |
Filter by specific showroom Outlet ID. If omitted or empty, returns all active outlets belonging to the company. |
Company_Id |
Integer |
Prohibited in Body |
Strictly derived from authenticated JWT context. Passing Company_Id in request triggers security rejection. |
Example Request Payloads
POST /api/v1/RestPerfectoService/GetOutlets
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{}
POST /api/v1/RestPerfectoService/GetOutlets
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Outlet list fetched successfully",
"data": [
{
"Outlet_Id": 1,
"Outlet_Name": "Surat Main Showroom",
"Company_Id": 1,
"Stock_Type": "JEWELLERY",
"Email": "surat@pristinejewels.com",
"Phone": "+91 261 2450001",
"Mobile": "+91 98250 12345",
"Address": "Ring Road, Surat",
"City": "Surat",
"Pin_Code": "395002",
"Is_Active": 1
},
{
"Outlet_Id": 2,
"Outlet_Name": "Ahmedabad Flagship Showroom",
"Company_Id": 1,
"Stock_Type": "JEWELLERY",
"Email": "ahmedabad@pristinejewels.com",
"Phone": "+91 79 2650002",
"Mobile": "+91 98250 54321",
"Address": "CG Road, Navrangpura",
"City": "Ahmedabad",
"Pin_Code": "380009",
"Is_Active": 1
}
]
}
Error Responses (HTTP 200 / 401 / 403)
// Scenario 1: Missing or Invalid Token (HTTP 401)
{
"status": "0",
"message": "Access denied. Token missing or invalid."
}
// Scenario 2: Anti-Tampering - Attempting to pass/override Company_Id in Request Body (HTTP 200)
{
"status": "0",
"message": "Company_Id and Credential_Id cannot be overridden in request."
}
// Scenario 3: Cross-Company Outlet Access (Selected Outlet does not belong to Company)
{
"status": "0",
"message": "Outlet does not belong to your company."
}
In Perfecto ERP, a Counter represents a distinct physical display showcase, sales counter, or jewellery tray inside a showroom (e.g., 'Gold Bangles Showcase', 'Bridal Diamond Counter 01').
COUNTER OPTIONALITY ARCHITECTURE:
- With Counter_Id: Stock is tracked at showcase counter level in
mst_counter_stock.
- Without Counter_Id: Stock operates outlet-wise directly in
mst_jewellery_stock_master. No Counter → stock works outlet-wise like before.
Creates a new showroom display counter record in mst_counter_master for a specific company outlet.
| Attribute |
Implementation Detail |
| Purpose |
Provision a new showroom display counter within the tenant's outlet |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/AddCounter |
| Service Namespace Status |
Production Implemented in RestPerfectoService (/AddCounter) |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Request Parameters (POST /api/admin/v1/AddCounter)
| Parameter |
Type |
Required |
Description |
Outlet_Id |
Integer |
Yes |
Target Outlet ID belonging to authenticated company |
Counter_Name |
String |
Yes |
Unique name of the display counter within the outlet (e.g., 'Gold-Counter-01') |
Counter_Code |
String |
Optional |
Short code or terminal tag (e.g., 'GC-01') |
Description |
String |
Optional |
Showroom location notes or showcase tier |
Company_Id |
Integer |
Derived |
Auto-resolved from authenticated JWT context (do not pass in request) |
Credential_Id |
Integer |
Derived |
Auto-resolved from authenticated JWT context (do not pass in request) |
Is_Active |
Integer |
Default |
Defaults to 1 upon creation in mst_counter_master |
Entry_IP |
String |
Audit |
Audit IP address of the client device automatically captured by middleware |
Example: POST /api/admin/v1/AddCounter Request Payload
POST /api/v1/RestPerfectoService/AddCounter
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1,
"Counter_Name": "Gold-Counter-01",
"Counter_Code": "GC-01"
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Counter added successfully.",
"data": {
"Counter_Id": 2,
"Counter_Name": "Gold-Counter-01",
"Counter_Code": "GC-01",
"Outlet_Id": 1,
"Company_Id": 1
}
}
Company & Outlet Validation Rules
- Tenant Boundary Enforcement: The backend resolves the authenticated operator's Company_Id and Outlet_Id from the session token. Non-superadmin users cannot create counters for other outlets.
- Name Uniqueness Check: The backend executes:
SELECT Counter_Id FROM mst_counter_master WHERE Outlet_Id = ? AND Company_Id = ? AND LOWER(Counter_Name) = LOWER(?) LIMIT 1. Attempting to add an existing name in the same outlet is rejected with HTTP 200 / status: 0 ('A counter with this name already exists in this outlet.').
- Counter_Id Generation Behavior: Upon successful insertion, the MariaDB auto-increment primary key (Counter_Id) is generated, Is_Active is set to 1, and the integer is returned in data.Counter_Id.
Error Responses (POST /api/admin/v1/AddCounter)
| Scenario |
HTTP Status |
status |
Server Error Message |
| Missing Counter_Name |
200 OK |
0 |
Counter_Name is required. |
| Duplicate Counter Name |
200 OK |
0 |
A counter with this name already exists in this outlet. |
| Cross-Company Outlet |
403 Forbidden |
0 |
Outlet does not belong to your company. |
| Missing / Expired Token |
401 Unauthorized |
0 |
Access token required / Invalid or expired token |
| Missing Outlet_Id |
200 OK |
0 |
Outlet_Id is required. |
Enables systems to discover and list showroom display counters for an outlet.
| Attribute |
Implementation Detail |
| Purpose |
Retrieve the collection of active showroom display counters for an outlet |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/GetCounters |
| Backward-Compatible Alias |
POST /api/v1/RestPerfectoService/GetOutletCounter |
| Real-Time Query Endpoint |
/api/v1/RestPerfectoService/Reports/StockCount |
| Service Namespace Status |
Implemented in RestPerfectoService (/GetCounters) |
| Authentication |
Third-Party Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Request Parameters (POST /api/admin/v1/OutletCountersList)
| Parameter |
Type |
Required |
Description |
Outlet_Id |
Integer |
Yes |
Target Outlet ID belonging to authenticated company |
Company_Id |
Integer |
Derived |
Auto-resolved from authenticated JWT context (do not pass in request) |
Credential_Id |
Integer |
Derived |
Auto-resolved from authenticated JWT context (do not pass in request) |
Example: POST /api/admin/v1/OutletCountersList Request Payload
POST /api/v1/RestPerfectoService/GetCounters
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1
}
Success Response (POST /api/admin/v1/OutletCountersList)
{
"status": "1",
"message": "Counters retrieved successfully.",
"data": {
"counters": [
{
"Counter_Id": 2,
"Outlet_Id": 1,
"Counter_Name": "Gold-Counter-01",
"Counter_Code": "GC-01",
"Is_Active": 1
},
{
"Counter_Id": 3,
"Outlet_Id": 1,
"Counter_Name": "Diamond-Showcase-01",
"Counter_Code": "DC-01",
"Is_Active": 1
}
],
"total_records": 2
}
}
Third-Party Live Counter Discovery (POST /Reports/StockCount)
Third-party POS and ERP clients calling the RestPerfectoService gateway can discover all active display counters and their live jewellery counts without admin credentials by calling POST /Reports/StockCount with their third-party Bearer token:
POST /api/v1/RestPerfectoService/Reports/StockCount
Authorization: Bearer <THIRD_PARTY_BEARER_TOKEN>
Content-Type: application/json
{
"Stock_Type": "JEWELLERY"
}
// Response returns all active counters for the authenticated showroom:
{
"status": "1",
"message": "Live stock count fetched successfully.",
"data": {
"Stock_Type": "JEWELLERY",
"Total_Live_Stock": 1420,
"Counters": [
{
"Counter_Id": 2,
"Counter_Name": "Gold-Counter-01",
"Stock_Count": 680
},
{
"Counter_Id": 3,
"Counter_Name": "Diamond-Showcase-01",
"Stock_Count": 740
}
]
}
}
Active / Inactive Counter Behavior & Filtering
- Active Counter Filtering: The query strictly enforces
WHERE Is_Active = 1. Deactivated counters are automatically suppressed from showroom POS workflows.
- Tenant Outlet Filtering: The query automatically limits results to the authenticated operator's Company_Id and Outlet_Id. Cross-tenant records are completely invisible.
- Counter_Id Operational Usage: The integer Counter_Id extracted from
data.List[].Counter_Id (or data.Counters[].Counter_Id) is the exact identifier required for all stock upload and operation APIs.
In Perfecto ERP, Counter_Id is the authoritative operational anchor linking jewellery SKU stock to showroom topology:
Batch-Level vs. Item-Level Counter Specification
- Batch-Level Specification (Recommended): Include
'Counter_Id': 2 at the top level of the JSON body. All items inside the 'Items' array are automatically assigned to this counter.
- Item-Level Override: Include
'Counter_Id': 3 inside individual item objects in the 'Items' array. Enables a single multi-counter synchronization payload.
Whenever stock is uploaded or modified via RestPerfectoService, the backend executes the resolveAndValidateCounter() engine inside transaction boundaries. The server strictly enforces the following verified validation rules:
| Validation Check |
Validation Rule |
HTTP Code |
Exact Server Error Message |
| Missing Counter_Id |
Optional: Omitted Counter_Id targets showroom inventory at outlet level |
200 OK |
Processed outlet-wise directly into mst_jewellery_stock_master. |
| Missing Outlet_Id |
Stock upload or operation invoked without Outlet_Id |
400 Bad Request |
Outlet_Id is required. |
| Invalid / Non-Integer |
Counter_Id is not a positive integer (e.g. "abc", -1, 0) |
200 OK |
Invalid Counter_Id '<val>'. Counter_Id must be a positive integer. |
| Counter Not Found |
Counter_Id does not exist in mst_counter_master |
200 OK |
Counter ID <val> not found. |
| Inactive Counter |
Counter record exists but Is_Active != 1 |
200 OK |
Counter '<Name>' (ID: <val>) is inactive. |
| Cross-Company Outlet |
Requested Outlet_Id does not belong to authenticated Company_Id |
403 Forbidden |
Outlet does not belong to your company. |
| Cross-Tenant Leakage |
Client attempts to manipulate another tenant's counter |
200 OK |
Strict isolation enforced; zero cross-tenant database leakage. |
The primary production endpoint for synchronizing showroom jewellery inventory. Implements non-destructive UPSERT (Inserts new stock; updates existing stock attributes; preserves unmentioned active showroom items).
| Attribute |
Implementation Detail |
| Purpose |
Synchronize jewellery inventory with non-destructive UPSERT and counter mapping |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/UploadStock |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Batch-Level Request Parameters
| Parameter |
Type |
Required |
Description |
Outlet_Id |
Integer |
Yes |
Target showroom outlet ID belonging to authenticated company. |
Reference_Id |
String |
Yes |
Client transaction ID (e.g. 'POS-2026-0926-001'). Enforces idempotency. |
Counter_Id |
Integer |
Optional |
Showroom display counter ID. Omit for outlet-wide inventory. |
Mode |
String |
Optional |
Synchronization mode: 'ADD' or 'SET' (both execute non-destructive UPSERT). |
Items |
Array |
Yes |
Array of Jewellery item objects to synchronize (minimum 1 item required). |
Jewellery Item Fields (inside Items array)
| Field Name |
Type |
Required |
Description |
Tag_No |
String |
Yes |
Unique jewellery SKU / item barcode tag. |
Item_Name |
String |
Yes |
Descriptive item name. |
Gross_Wt |
Decimal |
Yes |
Total gross weight in grams (positive decimal). |
Net_Wt |
Decimal |
Yes |
Pure precious metal weight in grams (Net_Wt <= Gross_Wt). |
Pcs |
Integer |
Yes |
Quantity of physical pieces (typically 1). |
Counter_Id |
Integer |
Optional |
Granular counter assignment override. Omit for outlet-wide inventory. |
Example: POST /UploadStock Request Payload
POST /api/v1/RestPerfectoService/UploadStock
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1,
"Reference_Id": "POS-SURAT-2026-001",
"Counter_Id": 2,
"Stock_Type": "JEWELLERY",
"Mode": "ADD",
"Items": [
{
"Tag_No": "JWL-RNG-001",
"Item_Name": "18K Gold Solitaire Ring",
"Category_Name": "Rings",
"Gross_Wt": 4.520,
"Net_Wt": 4.220,
"Stone_Wt": 0.300,
"Pcs": 1,
"Making_Charge": 3500.00,
"Stone_Amount": 125000.00
}
]
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Stock items processed successfully.",
"data": {
"upload_reference_id": "POS-SURAT-2026-001",
"outlet_id": 1,
"counter_id": 2,
"total_records_received": 1,
"inserted_count": 1,
"updated_count": 0,
"failed_count": 0,
"summary": {
"total_gross_weight": 4.520,
"total_net_weight": 4.220,
"total_pieces": 1
}
}
}
High-precision granular stock lifecycle engine. Enforces strict schema contracts, explicit operational modes, and granular counter mapping.
| Attribute |
Implementation Detail |
| Purpose |
Granular lifecycle management of individual jewellery items via explicit modes |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/StockOperation |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Supported Operational Modes
| Mode |
Operation Type |
Business Logic & Validation |
SET |
Atomic State Override |
Full state override of item attributes in stock master and counter stock. |
ADD |
Single Item Insert |
Dynamic insert of single item without requiring a full bulk batch. |
UPDATE |
Selective Update |
Updates supplied fields (e.g. Gross_Wt, Net_Wt, Remarks) on existing tag. |
REMOVE |
Soft Deactivation |
Sets Is_Active = 0 and Stock_Status = 'OUT' in stock master; clears counter stock. |
Outlet Scoping |
Outlet_Id Required |
Outlet_Id is required. Counter_Id is optional (targets counter stock if provided, outlet if omitted). |
Example: POST /StockOperation (UPDATE Mode) Request Payload
POST /api/v1/RestPerfectoService/StockOperation
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1,
"Operation_Mode": "UPDATE",
"Counter_Id": 2,
"Items": [
{
"Tag_No": "JWL-RNG-001",
"Gross_Wt": 4.510,
"Net_Wt": 4.210,
"Remarks": "Weight re-adjustment"
}
]
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Stock operation executed successfully.",
"data": {
"operation_mode": "UPDATE",
"outlet_id": 1,
"counter_id": 2,
"processed_count": 1,
"failed_count": 0,
"details": [
{
"tag_no": "JWL-RNG-001",
"status": "SUCCESS",
"message": "Stock item updated successfully."
}
]
}
}
Performs safe, transaction-bound soft-deactivation (Is_Active = 0) of all jewellery stock assigned to a specified showroom counter. Does NOT physically delete or purge database records.
| Attribute |
Implementation Detail |
| Purpose |
Soft-reset all active jewellery items mapped to a specific showroom display counter |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/ResetStock |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Request Parameters (POST /ResetStock)
| Parameter |
Type |
Required |
Description |
Outlet_Id |
Integer |
Yes |
Target showroom outlet identifier belonging to authenticated company. |
Counter_Id |
Integer |
Optional |
Showroom counter filter. If omitted, resets active stock across the entire outlet. |
Reference_Id |
String |
Recommended |
Client batch tracking identifier (e.g. 'POS-RESET-CTR-02'). |
Example: POST /ResetStock Request Payload
POST /api/v1/RestPerfectoService/ResetStock
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1,
"Counter_Id": 2
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Stock reset successfully.",
"data": {
"outlet_id": 1,
"counter_id": 2,
"archived_stock_count": 1420,
"cleared_counter_allocations": 1420,
"execution_timestamp": "2026-09-26 11:30:00"
}
}
Retrieves historical batch upload logs, processing timestamps, and synchronization metrics for the authenticated showroom.
| Attribute |
Implementation Detail |
| Purpose |
Query historical upload batch logs and item synchronization metrics |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/Reports/SessionSummary |
| Backward-Compatible Alias |
POST /api/v1/RestPerfectoService/GetSessionSummaryReport |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Request Parameters
| Parameter |
Type |
Required |
Description |
Limit |
Integer |
Optional |
Number of recent upload sessions to retrieve (default: 10, max: 100). |
Page |
Integer |
Optional |
Pagination page index (default: 1). |
Example: POST /Reports/SessionSummary Request Payload
POST /api/v1/RestPerfectoService/Reports/SessionSummary
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1,
"Limit": 10,
"Page": 1
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Session summary report fetched successfully.",
"token": "",
"data": {
"Total_Sessions": 12,
"Sessions": [
{
"Upload_History_Id": 145,
"Upload_Code": "UPLOAD-20260924-114830-1430",
"Reference_Id": "POS-SURAT-2026-001",
"Stock_Type": "JEWELLERY",
"Operation_Mode": "ADD",
"Total_Items": 2,
"Inserted_Items": 2,
"Updated_Items": 0,
"Failed_Items": 0,
"Status": "COMPLETED",
"Entry_Date": "2026-09-24 11:48:30"
}
]
}
}
Returns real-time active showroom inventory balances broken down by individual display counter.
| Attribute |
Implementation Detail |
| Purpose |
Fetch live count of active jewellery items grouped by showroom display counter |
| HTTP Method |
POST |
| Exact Endpoint |
/api/v1/RestPerfectoService/Reports/StockCount |
| Backward-Compatible Alias |
POST /api/v1/RestPerfectoService/GetLiveStockCount |
| Authentication |
Bearer Token (RestPerfectoServiceAuth.Middleware) |
| Headers |
Content-Type: application/json, Authorization: Bearer <TOKEN> |
Request Parameters
| Parameter |
Type |
Required |
Description |
Stock_Type |
String |
Optional |
Inventory category. Must be 'JEWELLERY' (defaults to JEWELLERY if omitted). |
Example: POST /Reports/StockCount Request Payload
POST /api/v1/RestPerfectoService/Reports/StockCount
Authorization: Bearer <ACCESS_TOKEN>
Content-Type: application/json
{
"Outlet_Id": 1,
"Stock_Type": "JEWELLERY"
}
Success Response (HTTP 200 OK)
{
"status": "1",
"message": "Live stock count fetched successfully.",
"token": "",
"data": {
"Stock_Type": "JEWELLERY",
"Total_Live_Stock": 1420,
"Counters": [
{
"Counter_Id": 2,
"Counter_Name": "Gold-Counter-01",
"Stock_Count": 680
},
{
"Counter_Id": 3,
"Counter_Name": "Diamond-Showcase-01",
"Stock_Count": 740
}
]
}
}
Third-party Point-of-Sale (POS) and ERP systems must implement the following standardized 7-step operational lifecycle when communicating with Perfecto ERP:
| Step # |
Integration Phase |
Target Endpoint |
Operational Rule & Best Practice |
| 1 |
Authenticate (Company) |
POST /Login |
Authenticate company credentials once every 24 hours. Cache JWT locally in memory. |
| 2 |
Discover Outlets |
POST /GetOutlets |
Query active company showrooms to resolve target Outlet_Id for inventory operations. |
| 3 |
Optional Counter Query |
POST /GetCounters |
Optional: Discover showroom display counters. If omitted, stock operates outlet-wise. |
| 4 |
Upload Stock |
POST /UploadStock |
Synchronize jewellery items with Outlet_Id, idempotency Reference_Id, and optional Counter_Id. |
| 5 |
Perform Operations |
POST /StockOperation |
Execute granular SET, ADD, UPDATE, or REMOVE operations scoped to Outlet_Id. |
| 6 |
Reset / Reconcile |
POST /ResetStock |
During physical audits, soft-deactivate outlet stock or specific counter inventory. |
| 7 |
Audit & Verify Balances |
POST /Reports/StockCount |
Verify stock counts and inspect automated audit logs in rest_perfecto_service_audit_logs. |
Architectural Sequence: 7-Step Integration Lifecycle
POS / ERP SYSTEM PERFECTO ERP GATEWAY
│ │
[1] ├── POST /Login ─────────────────────────────────────────────> │ Issue 24-Hour Company Bearer Token
│ <── HTTP 200 { token, expires_in: 86400 } ───────────────────┤
│ │
[2] ├── POST /GetOutlets {} ─────────────────────────────────────> │ Return Active Showrooms List
│ <── HTTP 200 { outlets: [ { Outlet_Id: 1, ... } ] } ────────┤
│ │
[3] ├── (Optional) POST /GetCounters { Outlet_Id: 1 } ───────────> │ Return Display Counters
│ <── HTTP 200 { counters: [ { Counter_Id: 2, ... } ] } ──────┤ (Or Omit for Outlet-wise)
│ │
[4] ├── POST /UploadStock { Outlet_Id: 1, [Counter_Id], Items } ─> │ Non-Destructive UPSERT
│ <── HTTP 200 { total_items, inserted_count, summary } ───────┤ (mst_jewellery_stock_master)
│ │
[5] ├── POST /StockOperation { Outlet_Id: 1, Mode, Items } ──────> │ Granular Operations
│ <── HTTP 200 { processed_count, details } ───────────────────┤ (SET, ADD, UPDATE, REMOVE)
│ │
[6] ├── POST /ResetStock { Outlet_Id: 1, [Counter_Id] } ─────────> │ Soft-Reset Inventory
│ <── HTTP 200 { archived_stock_count } ───────────────────────┤ (Mode: DELETE_ALL)
│ │
[7] ├── POST /Reports/StockCount { Outlet_Id: 1 } ───────────────> │ Audit Verification
│ <── HTTP 200 { Total_Live_Stock, Counters } ─────────────────┤ & rest_perfecto_service_audit_logs
RestPerfectoService uses standardized HTTP status codes in conjunction with explicit application status ("1" for success, "0" for rejected) and exact error messages.
| HTTP Status |
Scenario / Code |
Server Message Pattern |
Root Cause & Developer Action |
| 401 Unauthorized |
ERR_TOKEN_EXPIRED |
Access token expired. |
JWT TTL (1 hour) elapsed. Call POST /Login to acquire fresh token. |
| 401 Unauthorized |
ERR_TOKEN_MISSING |
No bearer token provided. |
Authorization header missing. Pass 'Authorization: Bearer <TOKEN>'. |
| 401 Unauthorized |
ERR_CRED_INACTIVE |
RestPerfectoService access is inactive. |
Credential disabled in Admin Portal. Contact Store Administrator. |
| 403 Forbidden |
ERR_OUTLET_CROSS_TENANT |
Outlet does not belong to your company. |
Cross-company access blocked. Target Outlet_Id must belong to authenticated company. |
| 400 Bad Request |
ERR_OUTLET_REQUIRED |
Outlet_Id is required. |
Payload omitted Outlet_Id. Supply target showroom Outlet_Id in request body. |
| 200 OK |
ERR_COUNTER_INVALID |
Invalid Counter_Id '<val>'. Must be positive int. |
Counter_Id format invalid. Pass a positive numeric integer. |
| 200 OK |
ERR_COUNTER_NOT_FOUND |
Counter ID <val> not found. |
Counter does not exist in database. Verify Counter_Id with Admin. |
| 200 OK |
ERR_COUNTER_INACTIVE |
Counter '<Name>' (ID: <val>) is inactive. |
Counter deactivated. Reactivate in Admin Portal before uploading. |
| 200 OK |
ERR_COUNTER_CROSS_TENANT |
Counter '<Name>' does not belong to Company/Outlet |
Cross-outlet counter passed. Pass Counter_Id belonging to your store. |
| 405 / 404 |
ERR_ENDPOINT_INVALID |
Method Not Allowed or Endpoint Not Found |
Unmapped route or wrong HTTP method. Verify exact endpoint URL. |
All documented APIs and operational constraints have undergone comprehensive automated verification against the Perfecto backend engine. Test cases for Counter Add and Counter List have been verified and documented separately below:
| Subsystem / Test Case |
Endpoint Tested |
Test Description & Inputs |
Result |
Verified Output Metric |
| Counter: Add Valid |
POST /api/admin/v1/AddCounter |
Valid counter name, code, description, operators |
PASS |
HTTP 200, status: 1, Counter_Id generated |
| Counter: Add Duplicate |
POST /api/admin/v1/AddCounter |
Duplicate Counter_Name in same outlet |
PASS |
HTTP 200, status: 0, Unique constraint held |
| Counter: Add Missing Name |
POST /api/admin/v1/AddCounter |
Payload omitted Counter_Name |
PASS |
HTTP 200, status: 0, 'Counter_Name is required.' |
| Counter: List Active |
POST /api/admin/v1/OutletCountersList |
Query counters for authenticated outlet |
PASS |
HTTP 200, status: 1, Active counter array |
| Counter: List Filtered |
POST /api/admin/v1/CounterList |
Management query with Is_Active = 1 filter |
PASS |
HTTP 200, status: 1, Total_Active_Stock returned |
| Counter: Third-Party Query |
POST /Reports/StockCount |
Query live showroom counters via third-party token |
PASS |
HTTP 200, status: 1, Counters array populated |
| Auth: Login Success |
POST /Login |
Valid assigned service credentials |
PASS |
HTTP 200, status: 1, JWT Bearer token issued |
| Auth: Bad Password |
POST /Login |
Invalid credential password |
PASS |
HTTP 200, status: 0, 'Invalid username or password.' |
| Upload: Jewellery UPSERT |
POST /UploadStock |
2 jewellery items with batch Counter_Id = 2 |
PASS |
HTTP 200, 2 inserted, mst_counter_stock mapped |
| Upload: Idempotency |
POST /UploadStock |
Re-submitting identical Reference_Id |
PASS |
HTTP 200, Cached response returned instantly |
| Upload: Missing Counter |
POST /UploadStock |
Payload omitted Counter_Id |
PASS |
HTTP 200, status: 0, ERR_COUNTER_REQUIRED rejection |
| Upload: Cross-Tenant |
POST /UploadStock |
Counter_Id belonging to different outlet |
PASS |
HTTP 200, status: 0, Tenant boundary protected |
| Operation: UPDATE |
POST /StockOperation |
UPDATE mode modifying item description |
PASS |
HTTP 200, Updated_Items: 1, non-destructive |
| Reset: Counter Reset |
POST /ResetStock |
Counter_Id = 2 soft-deactivation |
PASS |
HTTP 200, Deleted_Items: 2, Is_Active = 0 |
| Reset: Missing Counter |
POST /ResetStock |
ResetStock invoked without Counter_Id |
PASS |
HTTP 200, status: 0, Safety lock held |
| Reports: Session Summary |
POST /Reports/SessionSummary |
Query recent upload audit logs |
PASS |
HTTP 200, Sessions array returned |
| Reports: Stock Count |
POST /Reports/StockCount |
Query active stock count grouped by counter |
PASS |
HTTP 200, Real-time counter totals |