Payment Voucher
A payment voucher records money paid out, normally settling one or more purchase invoices. Like every financial document it uses the shared document API, with the document type as a path segment.
Base path: https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc
Path segment ({docType}): internal-payment-vouchers
server_doc_type field value: INTERNAL_PAYMENT_VOUCHER
See ERP Core API for authentication, the response envelope, and shared query parameters. The Purchase Invoice page documents the shared container and the full endpoint set; this page covers what is specific to payment vouchers.
server_doc_type field. The URL takes internal-payment-vouchers; the field inside the document takes INTERNAL_PAYMENT_VOUCHER. Putting the upper-case form in the URL returns 404, which reads as “no such document” rather than “no such route”. The body varies by endpoint: query and get-by-guid return an empty body, while create and delete return {"code": "OK_NODATA", ...}, an “OK” code on a 404.A related type, internal-reimbursement-payment-vouchers (INTERNAL_REIMBURSEMENT_PAYMENT_VOUCHER), uses exactly the same endpoints with its own permission set.
Permissions
| Operation | Permission |
|---|---|
| Create | TNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_CREATE_TGT_GUID |
| Read | TNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_READ_TGT_GUID |
| Update | TNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_UPDATE_TGT_GUID |
| Delete | TNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_DELETE_TGT_GUID |
Permission names keep the upper-case singular form. These are target-scoped against the document’s guid_comp, guid_branch, guid_store and guid_store_2. See the note on the purchase invoice page.
Endpoints
Identical to the purchase invoice endpoints with internal-payment-vouchers as {docType}. The ones you will use most:
| Operation | Path (relative to the base path) |
|---|---|
| Create | POST /internal-payment-vouchers/etl-ep |
| Create several | POST /internal-payment-vouchers/etl-ep/multi |
| Update | PUT /internal-payment-vouchers/etl-ep |
| Delete | DELETE /internal-payment-vouchers/etl-ep/{guid} |
| List all | GET /internal-payment-vouchers/etl-ep |
| Get one | GET /internal-payment-vouchers/etl-ep/{guid} |
| Query | GET /internal-payment-vouchers/etl-ep/query |
| Set posting status | PUT /internal-payment-vouchers/etl-ep/update-posting-status/{guid} |
| Void | PUT /internal-payment-vouchers/etl-ep/void/{guid} |
| Discard | PUT /internal-payment-vouchers/discard/etl-ep/{guid} |
| Purge | DELETE /internal-payment-vouchers/purge/etl-ep/{guid} |
| Print to PDF | GET /internal-payment-vouchers/etl-ep/print-jasper-pdf/{guid} |
Settlement against invoices uses a separate endpoint group, covered under Settling invoices:
| Operation | Path |
|---|---|
| Create a contra | POST /arap-contras/etl-ep |
| Recalculate | PUT /arap-contras/recalculation/etl-ep |
| Delete a contra | DELETE /arap-contras/etl-ep/{guid} |
| List all | GET /arap-contras/etl-ep |
| Get one | GET /arap-contras/etl-ep/{guid} |
| Query | GET /arap-contras/etl-ep/query |
How a payment voucher is put together
A payment voucher is not one object. It is three things, and getting this wrong is the main reason a voucher fails validation:
- The header, carrying the supplier, company, currency and totals.
- Lines, which come in two kinds: what is being paid, and how it is being paid.
- ARAP contra rows, which attach the voucher to the specific invoices it settles. These are created separately, through their own endpoint.
The two kinds of line
Every line carries a txn_type saying which kind it is. Both values are platform constants, not tenant configuration.
txn_type | Meaning | Key fields |
|---|---|---|
PNS | What is being paid: the payable amount. | amount_txn, quantity_base, item_guid, item_code, arap_pns_amount |
STL_MTHD | How it is being paid: one row per settlement method. | amount_txn, cashbook_guid, settlement_type, item_guid, item_code |
Line signums are set for you. On a payment voucher the server assigns amount_signum of 1 and quantity_signum of 0 to every line, on create and on update, so you can leave both out of your payload. server_doc_type is likewise inherited from the header.
Existing vouchers may show different line signums, so build from the values above rather than copying an older record.
cashbook_guid lives on the STL_MTHD line, not on the header. That is how a voucher says which cashbook the money leaves from. A voucher paid half by bank transfer and half in cash has two STL_MTHD lines, each naming its own cashbook.settlement_type accepts CASH, BANK_TRANSFER, CHEQUE, E_WALLET, CREDIT_CARD, DEBIT_CARD, VOUCHER and OTHERS.
Both line kinds require item_guid and item_code. For a STL_MTHD line the item is the settlement-method item, an item record whose txn_class is STL_MTHD. Look yours up before building a voucher.
Keeping the two sides balanced
A voucher’s PNS total should equal its STL_MTHD total, allowing for any amounts offset by ARAP contra. What you are paying and what you are paying it with need to agree.
The API does not check this for you on a payment voucher, so build the balance in as you construct the document rather than relying on the create call to catch it.
The container
The GenericDocumentContainer is the same shape. What differs is which parts you populate.
bl_fi_generic_doc_hdr: payment voucher fields
| Field | Type | On create | Description |
|---|---|---|---|
guid | UUID | Optional | Generated if omitted. Required on update. |
guid_comp | UUID | Required | Paying company. Also a permission target. |
guid_store | UUID | Required | Store/location. Also a permission target. |
guid_branch | UUID | Optional | Branch. Also a permission target. |
doc_entity_hdr_guid | UUID | Required | The supplier being paid. |
doc_ccy | string | Recommended | Payment currency, e.g. MYR. |
date_txn | datetime | Recommended | Payment date. Defaults to now. |
doc_reference | string | Optional | Cheque number, transfer reference, or similar. |
doc_desc, doc_remarks | string | Optional | Description and free-text remarks. |
server_doc_type | string | Required | INTERNAL_PAYMENT_VOUCHER. Required on the header; it is not inferred from the URL. Lines inherit it. |
amount_txn | decimal | Recommended | Amount paid, as a negative number on the header (money out). |
amount_net | decimal | Recommended | Net amount, also negative. |
amount_signum | decimal | Required | 1 on the payment voucher header. Validated on the header only. |
amount_internal_settlement | decimal | Server-maintained | Amount applied against outstanding documents. |
amount_open_balance | decimal | Server-maintained | Remaining unapplied amount. |
arap_stlm_amount, arap_doc_open, arap_bal | decimal | Server-maintained | AR/AP settlement tracking. |
posting_status | string | Optional | DRAFT or FINAL. |
posting_cashbook, posting_journal | string | Server-maintained | Whether each posting has run. |
status | string | Optional | Defaults to ACTIVE. |
revision | UUID | Optional | Generated if omitted. Send the value you read back when updating. |
client_key, client_source | string | Optional | Your system’s identifiers. |
client_doc_1 … client_doc_5 | string | Optional | Your own document references. |
property_json | object | Optional | Arbitrary extra properties. |
server_doc_1 … server_doc_5 | string | Server-assigned | Running numbers generated by BigLedger. |
pin_code, pin_type, pin_hash, pin_algorithm | string | Server-assigned | Generated on create when no PIN is supplied. Do not set these. |
bl_fi_generic_doc_line
Present on every line of both kinds: guid, generic_doc_hdr_guid, guid_comp, guid_store, txn_type, item_guid, item_code, item_name, amount_txn, amount_net, amount_signum, quantity_signum, status, revision, plus the server-assigned audit columns.
Additionally on STL_MTHD lines: cashbook_guid (always), settlement_type, arap_stlm_amount, arap_pns_amount, unit_price_net, unit_price_txn.
Additionally on PNS lines: quantity_base, amount_std, amount_discount, arap_pns_amount, arap_stlm_amount, item_sub_type, item_txn_type, guid_branch, and optionally guid_glcode.
Settling invoices
Attaching a voucher to the invoices it pays is a separate call against the ARAP contra endpoint. It is not part of the voucher body.
Base path: https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/arap-contras
{ "bl_fi_generic_doc_arap_contra": { } }| Field | Type | Description |
|---|---|---|
guid | UUID | Generated if omitted. |
guid_doc_1_hdr | UUID | Required. One of the two documents. |
server_doc_type_doc_1 | string | Its server_doc_type, upper-case form. Recommended. |
guid_doc_2_hdr | UUID | Required. The other document. |
server_doc_type_doc_2 | string | Its server_doc_type, upper-case form. Recommended. |
amount_contra | decimal | Required. Amount applied between the two. |
date_txn, date_doc_1, date_doc_2 | datetime | Optional dates. |
status | string | Defaults to ACTIVE. |
revision | UUID | Generated if omitted. |
posting_status, posting_journal, posting_arap | string | Posting state. |
forex_doc_hdr_guid, forex_gain_loss_base | UUID / decimal | Foreign-exchange gain or loss, where relevant. |
doc_remarks | string | Optional remarks. |
client_source, gen_doc_client_key_1, gen_doc_client_value_1, gen_doc_client_key_2, gen_doc_client_value_2 | string | Your own correlation identifiers. |
The pairing is not order-sensitive: both INTERNAL_PURCHASE_INVOICE as doc 1 and as doc 2 occur in live data.
Post contras one at a time. Bulk contra creation is available to the back-office applet through POST /arap-contras/multi/backoffice-ep, but there is no /etl-ep equivalent yet.
POST /arap-contras/etl-ep/multi is not a contra endpoint. It matches the generic document route and expects a list of GenericDocumentContainer, so use the single-contra POST /arap-contras/etl-ep instead.
Document lifecycle
Same as a purchase invoice:
| Value | Meaning |
|---|---|
DRAFT | Created but not posted. Freely editable. |
FINAL | Posted. Cashbook, journal and AP settlement entries are written. |
Create as DRAFT, verify the lines and contras, then move to FINAL. To cancel a finalized voucher, void it: that reverses the settlement and puts the balance back on the invoice. Deleting a posted voucher does not.
Create a payment voucher
POST /core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-epThe example below pays a 1,060.00 purchase invoice in full, by bank transfer from a single cashbook.
curl -X POST "https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/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_generic_doc_hdr": {
"server_doc_type": "INTERNAL_PAYMENT_VOUCHER",
"guid_comp": "3f2a7c10-9b4e-4d61-8a22-1c5e7f9d0b33",
"guid_store": "6b8d1f42-7e35-4c09-ad81-1d4e8b2c5a70",
"doc_entity_hdr_guid": "e7b2d48f-1c93-4a05-8e67-4f9a3b1d5c26",
"doc_source_type": "INTERNAL",
"doc_ccy": "MYR",
"date_txn": "2026-10-10T00:00:00+08:00",
"doc_reference": "TRF-20261010-0031",
"doc_desc": "Payment for PI-2026-000042",
"amount_net": -1060.00,
"amount_txn": -1060.00,
"amount_signum": 1,
"posting_status": "DRAFT",
"status": "ACTIVE"
},
"bl_fi_generic_doc_line": [
{
"txn_type": "PNS",
"item_guid": "2d7f9b04-6c31-4a85-9e12-8b3d5f7a1c60",
"item_code": "AP-SETTLE",
"item_name": "Accounts payable settlement",
"quantity_base": 1,
"amount_std": 1060.00,
"amount_net": 1060.00,
"amount_txn": 1060.00
},
{
"txn_type": "STL_MTHD",
"item_guid": "5a1c8e36-9d24-4f70-b83e-2c6f4a9b7d51",
"item_code": "STL-BANK",
"item_name": "Bank transfer",
"settlement_type": "BANK_TRANSFER",
"cashbook_guid": "1a7e9c53-6b28-4d90-8f41-5c3b7a2e6d19",
"amount_net": 1060.00,
"amount_txn": 1060.00
}
],
"bl_fi_generic_doc_ext": [],
"bl_fi_generic_doc_link": [],
"bl_fi_generic_doc_event": []
}'```
Keep the returned `guid`. `server_doc_1` stays null while the voucher is `DRAFT`; running numbers are assigned at finalization.
Then attach it to the invoice it pays:
```bash
curl -X POST "https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/arap-contras/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_generic_doc_arap_contra": {
"guid_doc_1_hdr": "4d8b2f61-3a07-4e95-b12c-7f6a9d3e5c84",
"server_doc_type_doc_1": "INTERNAL_PURCHASE_INVOICE",
"guid_doc_2_hdr": "7e3c9a52-4b18-4f70-8d26-5a1f8c3b6e94",
"server_doc_type_doc_2": "INTERNAL_PAYMENT_VOUCHER",
"amount_contra": 1060.00,
"date_txn": "2026-10-10T00:00:00+08:00",
"status": "ACTIVE"
}
}'Finalize a payment voucher
PUT /core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-ep/update-posting-status/{guid}curl -X PUT "https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-ep/update-posting-status/7e3c9a52-4b18-4f70-8d26-5a1f8c3b6e94" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
-H "Content-Type: application/json" \
-d '{"posting_status": "FINAL"}'Once this returns, re-read the purchase invoice: its amount_open_balance should have dropped by the settled amount. That is the quickest end-to-end check that your integration is wired up correctly.
Void a payment voucher
PUT /core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-ep/void/{guid}curl -X PUT "https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-ep/void/7e3c9a52-4b18-4f70-8d26-5a1f8c3b6e94" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
-H "Content-Type: application/json" \
-d '{}'Voiding reverses the settlement: the invoice’s outstanding balance goes back up.
Query payment vouchers
GET /core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-ep/queryTakes the same criteria as purchase invoices. For vouchers, has_line=true is the flag that matters, since the lines carry the settlement detail. Vouchers do not use bl_fi_generic_doc_link, so has_link=true adds nothing here.
curl -G "https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/internal-payment-vouchers/etl-ep/query" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
--data-urlencode "doc_entity_hdr_guid=e7b2d48f-1c93-4a05-8e67-4f9a3b1d5c26" \
--data-urlencode "hdr_posting_status=FINAL" \
--data-urlencode "has_line=true" \
--data-urlencode "limit=50" \
--data-urlencode "calcTotalRecords=true"To see which invoices a voucher settled, query the contras instead:
curl -G "https://api-etl.akaun.com/core2/tnt/dm/erp/gen-doc/arap-contras/etl-ep/query" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
--data-urlencode "limit=50" \
--data-urlencode "calcTotalRecords=true"