Ledger
A ledger is the book a company keeps its postings in, scoped to one company and one currency and linked to a chart-of-account record.
Base path: https://api-etl.akaun.com/core2/tnt/dm/erp/fi/ledgers
See ERP Core API for authentication, the response envelope, and shared query parameters.
Permissions
The access key’s owner needs one of these for each operation:
| Operation | Permissions (any one) |
|---|---|
| Create | API_TNT_DM_ERP_FI_MST_LEDGER_OWNER, API_TNT_DM_ERP_FI_MST_LEDGER_ADMIN, API_TNT_DM_ERP_FI_MST_LEDGER_CREATE |
| Read | ..._LEDGER_OWNER, ..._LEDGER_ADMIN, API_TNT_DM_ERP_FI_MST_LEDGER_READ |
| Update | ..._LEDGER_OWNER, ..._LEDGER_ADMIN, API_TNT_DM_ERP_FI_MST_LEDGER_UPDATE |
| Delete | ..._LEDGER_OWNER, ..._LEDGER_ADMIN, API_TNT_DM_ERP_FI_MST_LEDGER_DELETE |
A tenant owner or admin passes all of these regardless.
Endpoints
| Operation | Integration path (/etl-ep) | Back-office path |
|---|---|---|
| Create | POST /etl-ep | POST / |
| Update | PUT /etl-ep | PUT / |
| Delete | DELETE /etl-ep/{guid} | DELETE /{guid} |
| List all | GET /etl-ep | GET / |
| Get one | GET /etl-ep/{guid} | GET /{guid} |
| Query | GET /etl-ep/query | GET /query |
The LedgerContainer
Every request body and response data object is a LedgerContainer:
{
"bl_fi_mst_ledger_hdr": { },
"bl_fi_mst_ledger_exts": [ ]
}bl_fi_mst_ledger_exts holds optional extension rows and may be omitted or empty.
bl_fi_mst_ledger_hdr
| Field | Type | On create | Description |
|---|---|---|---|
guid | UUID | Optional | Generated if omitted. Required on update. |
guid_comp | UUID | Required | The company this ledger belongs to. |
obj_type | string | Required | PRM for the company’s primary ledger, SEC for a secondary one. See below. |
name | string | Recommended | Display name. |
code | string | Recommended | Short code. |
ccy_code | string | Optional | Currency, e.g. MYR. |
chart_of_acc_hdr_guid | UUID | Optional | Link to a chart of accounts record. Not normally set. |
property_json | object | Optional | Arbitrary extra properties. Defaults to {}. |
status | string | Optional | Defaults to ACTIVE. |
namespace | string | Optional | Namespace for multi-app tenants. |
module_guid | UUID | Optional | Owning module. |
applet_guid | UUID | Optional | Owning applet. |
acl_config | object | Optional | Access-control configuration. |
acl_policy | object | Optional | Access-control policy. |
revision | UUID | Optional | Generated if omitted, and regenerated on every update. |
vrsn | string | Server-assigned | Version marker. |
created_date | datetime | Server-assigned on create | Must be sent back on update. |
updated_date | datetime | Server-assigned | |
created_by_subject_guid | UUID | Server-assigned on create | Set from the access key’s owner. Must be sent back on update. |
updated_by_subject_guid | UUID | Server-assigned | Set from the access key’s owner. |
Only guid_comp and obj_type are required on create. A request carrying just those two succeeds.
A company may have only one PRM ledger. Creating a second primary ledger for the same guid_comp fails with API_TNT_DM_ERP_FI_MST_LEDGER_HDR_OBJECT_PRIMARY_LEDGER_ALREADY_EXISTS. Since most companies already have theirs, a ledger you create through the API will normally be SEC.
Omitting obj_type entirely fails with API_TNT_DM_ERP_FI_MST_LEDGER_HDR_OBJECT_OBJ_TYPE_IS_NULL_OR_EMPTY.
Create a ledger
POST /core2/tnt/dm/erp/fi/ledgers/etl-epcurl -X POST "https://api-etl.akaun.com/core2/tnt/dm/erp/fi/ledgers/etl-ep" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
-H "Content-Type: application/json" \
-d '{
"bl_fi_mst_ledger_hdr": {
"name": "Secondary Ledger MYR",
"code": "GL-SEC-MYR",
"guid_comp": "3f2a7c10-9b4e-4d61-8a22-1c5e7f9d0b33",
"obj_type": "SEC",
"ccy_code": "MYR"
},
"bl_fi_mst_ledger_exts": []
}'Response: 200 OK with the created container. guid, status and revision are filled in for you:
{
"code": "OK_RESPONSE",
"data": {
"bl_fi_mst_ledger_hdr": {
"guid": "c4f9a2e8-5b31-4c78-9d06-2a8f1e7b3c95",
"name": "Secondary Ledger MYR",
"code": "GL-SEC-MYR",
"guid_comp": "3f2a7c10-9b4e-4d61-8a22-1c5e7f9d0b33",
"obj_type": "SEC",
"ccy_code": "MYR",
"property_json": {},
"status": "ACTIVE",
"revision": "7a2c9e14-8f35-4b60-a1d7-3c8b5f2e9d04",
"created_date": "2026-09-14T13:31:43.931410146Z",
"created_by_subject_guid": "1c76c817-d6ac-4058-81f3-87805600e583"
},
"bl_fi_mst_ledger_exts": []
},
"message": ""
}Update a ledger
PUT /core2/tnt/dm/erp/fi/ledgers/etl-epRead the record first, modify it, and send the whole thing back. Update validation expects fields that are assigned by the server on create, so a hand-built payload is likely to be rejected.
On update, obj_type, created_date and created_by_subject_guid are all required alongside guid. Omitting them returns three errors at once:
API_TNT_DM_ERP_FI_MST_LEDGER_HDR_OBJECT_OBJ_TYPE_IS_NULL_OR_EMPTY
API_TNT_DM_ERP_FI_MST_LEDGER_HDR_OBJECT_CREATED_DATE_IS_NULL_OR_EMPTY
API_TNT_DM_ERP_FI_MST_LEDGER_HDR_OBJECT_CREATED_BY_SUBJECT_GUID_IS_NULLFields you leave out are not preserved, so round-tripping the record is the reliable approach.
# 1. read it
curl -s "https://api-etl.akaun.com/core2/tnt/dm/erp/fi/ledgers/etl-ep/c4f9a2e8-5b31-4c78-9d06-2a8f1e7b3c95" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE"
# 2. change what you need inside data.bl_fi_mst_ledger_hdr, keep every other field,
# then send the whole container back
curl -X PUT "https://api-etl.akaun.com/core2/tnt/dm/erp/fi/ledgers/etl-ep" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
-H "Content-Type: application/json" \
-d '{
"bl_fi_mst_ledger_hdr": {
"guid": "c4f9a2e8-5b31-4c78-9d06-2a8f1e7b3c95",
"name": "Secondary Ledger MYR (revised)",
"code": "GL-SEC-MYR",
"guid_comp": "3f2a7c10-9b4e-4d61-8a22-1c5e7f9d0b33",
"obj_type": "SEC",
"ccy_code": "MYR",
"status": "ACTIVE",
"revision": "7a2c9e14-8f35-4b60-a1d7-3c8b5f2e9d04",
"created_date": "2026-09-14T13:31:43.931410146Z",
"created_by_subject_guid": "1c76c817-d6ac-4058-81f3-87805600e583"
},
"bl_fi_mst_ledger_exts": []
}'Permission on update is also checked against the specific ledger, so a user granted ..._UPDATE on one ledger only cannot modify another.
Delete a ledger
DELETE /core2/tnt/dm/erp/fi/ledgers/etl-ep/{guid}curl -X DELETE "https://api-etl.akaun.com/core2/tnt/dm/erp/fi/ledgers/etl-ep/c4f9a2e8-5b31-4c78-9d06-2a8f1e7b3c95" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE"Response
{ "code": "OK_RESPONSE", "data": true, "message": "" }Returns 404 with CLIENT_VALIDATION_GUID_DOES_NOT_EXIST if no such ledger exists.
PRM ledger cannot be deleted. A company’s primary ledger is protected, and the attempt is returned as 404 CLIENT_VALIDATION_GUID_DOES_NOT_EXIST, the same response as a GUID that does not exist. If a delete returns 404 on a ledger you know is there, check its obj_type.List all ledgers
GET /core2/tnt/dm/erp/fi/ledgers/etl-epReturns every ledger the key’s owner may read, as a streamed array. There is no paging on this endpoint. Use /etl-ep/query when you need to page.
Get one ledger
GET /core2/tnt/dm/erp/fi/ledgers/etl-ep/{guid}Returns a single LedgerContainer, 403 if the key’s owner lacks read permission on that record, or 404 if it does not exist.
Query ledgers
GET /core2/tnt/dm/erp/fi/ledgers/etl-ep/queryIn addition to the shared query parameters:
| Parameter | Type | Description |
|---|---|---|
guid_comp | UUID | Filter by company. |
ccy_code | string | Filter by currency. |
chart_of_acc_hdr_guid | UUID | Filter by chart-of-account record. |
name | string | Exact name match. |
code | string | Exact code match. |
obj_type | string | Filter by ledger type. |
guids | UUID set | Fetch a specific set of ledgers. Repeat the parameter. |
hdr_guid | UUID | Filter extension rows by their header. |
namespace | string | Filter by namespace. |
module_guid | UUID | Filter by module. |
applet_guid | UUID | Filter by applet. |
ext_guids | UUID set | Filter by extension GUIDs. Repeat the parameter. |
revision | UUID | Filter by revision. |
vrsn | string | Filter by version. |
curl -G "https://api-etl.akaun.com/core2/tnt/dm/erp/fi/ledgers/etl-ep/query" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
--data-urlencode "ccy_code=MYR" \
--data-urlencode "status=ACTIVE" \
--data-urlencode "limit=50" \
--data-urlencode "calcTotalRecords=true"Response
{
"code": "OK_RESPONSE",
"data": [
{
"bl_fi_mst_ledger_hdr": {
"guid": "c4f9a2e8-5b31-4c78-9d06-2a8f1e7b3c95",
"name": "General Ledger MYR",
"code": "GL-MYR",
"ccy_code": "MYR",
"status": "ACTIVE"
},
"bl_fi_mst_ledger_exts": []
}
],
"totalRecords": 3,
"offset": 0,
"limit": 50,
"message": ""
}