Sage 200 Evolution ERP Integration
Freedom Service REST SDK, Agent permissions, and idempotency key mapping.
This guide describes how to connect KHOLO to Sage 200 Evolution (and Sage Pastel Partner) using the official Freedom Service REST API SDK.
1. Integration Architecture
Kholo Backend & ERP Adapter
Translates verified order lines, assigns order.id as the idempotency key, and dispatches JSON payload.
Sage Freedom Service & SQL
Creates Sales Order (SO-2026-XXXX), reserves warehouse inventory, and enforces customer credit limits.
2. Prerequisites & Server Setup
Before configuring Kholo, ensure the distributor's IT team has configured:
- Sage Freedom Service REST API: Installed on the Sage application server and listening on an accessible port (default
8080). - Dedicated Agent Account: Create an Evolution Agent named
kholo_agentwith:- Sales Order Entry permissions (
POST /SalesOrder). - Read access to Customer Master (
GET /Customer) and Inventory Master (GET /Inventory).
- Sales Order Entry permissions (
- Firewall / VPN: Secure the Freedom Service port so that only Kholo's static outbound IP addresses can communicate with it.
3. Configuring the ERP Connection in Kholo
In the Kholo web portal, navigate to Settings $\rightarrow$ ERP Configuration or update the erpConfig JSON in the Tenant database record:
{
"type": "sage_evolution",
"endpoint": "http://192.168.X.X:8080/Freedom.Core/METRO_DB/SDK/Rest",
"branchCode": "001",
"warehouseCode": "001",
"agentCode": "kholo_agent",
"agentPassword": "EncryptedPasswordHere",
"idempotencyKey": "ExternalOrderNo"
}4. Sales Order REST Payload Structure
When an order is approved, SageEvolutionConnector constructs and posts the following payload:
{
"Header": {
"CustomerAccount": "CUST-8832",
"ExternalOrderNo": "997220b1-3d2e-4fad-a758-fb0fe872aeb0",
"OrderDate": "2026-09-30",
"DeliveryAddress": {
"CustomerName": "Clerk (KwaMashu Spaza)",
"ContactPhone": "+27 00 000 0000"
},
"BranchCode": "001",
"Source": "Kholo WhatsApp Middleware",
"Notes": "Automated WhatsApp Order: 10 whites 12.5kg, 4 tastic 10kg"
},
"Lines": [
{
"LineNumber": 1,
"ItemCode": "WSTAR-12.5KG",
"Description": "White Star Maize Meal 12.5kg",
"Quantity": 10,
"UnitPrice": 148.50,
"TaxType": 2,
"WarehouseCode": "001"
},
{
"LineNumber": 2,
"ItemCode": "TASTIC-10KG",
"Description": "Tastic Parboiled Rice 10kg",
"Quantity": 4,
"UnitPrice": 215.00,
"TaxType": 2,
"WarehouseCode": "001"
}
]
}5. Strict Idempotency Handling
To prevent duplicate sales orders caused by network retries, connection drops, or multiple clerk clicks:
ExternalOrderNoMapping: Kholo assigns its internal UUID (order.id) toExternalOrderNoin Sage Evolution.- Pre-Flight Duplicate Check: If
order.erpSalesOrderIdalready exists on the Kholo order, the system skips the HTTP call and returns the existing order reference immediately:if (order.erpSalesOrderId) { return { success: true, erpSalesOrderId: order.erpSalesOrderId, idempotent: true }; } - Database Conflict Resolution: Sage Freedom Service rejects any secondary request containing an existing
ExternalOrderNo, returning the original order reference.
6. Verifying the Connection (Smoke Test)
You can verify communication with the Sage Evolution instance from the command line:
cd apps/api
npx ts-node src/scripts/verify-readiness.tsExpected confirmation:
[CHECK 5/6] Sage ERP & Pick Slip: PASS (SO Format: SO-2026-XXXX, Pick Slip: 3 lines)