Skip to content

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.

The path segment is not the same string as the 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

OperationPermission
CreateTNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_CREATE_TGT_GUID
ReadTNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_READ_TGT_GUID
UpdateTNT_API_DOC_INTERNAL_PAYMENT_VOUCHER_UPDATE_TGT_GUID
DeleteTNT_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:

OperationPath (relative to the base path)
CreatePOST /internal-payment-vouchers/etl-ep
Create severalPOST /internal-payment-vouchers/etl-ep/multi
UpdatePUT /internal-payment-vouchers/etl-ep
DeleteDELETE /internal-payment-vouchers/etl-ep/{guid}
List allGET /internal-payment-vouchers/etl-ep
Get oneGET /internal-payment-vouchers/etl-ep/{guid}
QueryGET /internal-payment-vouchers/etl-ep/query
Set posting statusPUT /internal-payment-vouchers/etl-ep/update-posting-status/{guid}
VoidPUT /internal-payment-vouchers/etl-ep/void/{guid}
DiscardPUT /internal-payment-vouchers/discard/etl-ep/{guid}
PurgeDELETE /internal-payment-vouchers/purge/etl-ep/{guid}
Print to PDFGET /internal-payment-vouchers/etl-ep/print-jasper-pdf/{guid}

Settlement against invoices uses a separate endpoint group, covered under Settling invoices:

OperationPath
Create a contraPOST /arap-contras/etl-ep
RecalculatePUT /arap-contras/recalculation/etl-ep
Delete a contraDELETE /arap-contras/etl-ep/{guid}
List allGET /arap-contras/etl-ep
Get oneGET /arap-contras/etl-ep/{guid}
QueryGET /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:

  1. The header, carrying the supplier, company, currency and totals.
  2. Lines, which come in two kinds: what is being paid, and how it is being paid.
  3. 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_typeMeaningKey fields
PNSWhat is being paid: the payable amount.amount_txn, quantity_base, item_guid, item_code, arap_pns_amount
STL_MTHDHow 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

FieldTypeOn createDescription
guidUUIDOptionalGenerated if omitted. Required on update.
guid_compUUIDRequiredPaying company. Also a permission target.
guid_storeUUIDRequiredStore/location. Also a permission target.
guid_branchUUIDOptionalBranch. Also a permission target.
doc_entity_hdr_guidUUIDRequiredThe supplier being paid.
doc_ccystringRecommendedPayment currency, e.g. MYR.
date_txndatetimeRecommendedPayment date. Defaults to now.
doc_referencestringOptionalCheque number, transfer reference, or similar.
doc_desc, doc_remarksstringOptionalDescription and free-text remarks.
server_doc_typestringRequiredINTERNAL_PAYMENT_VOUCHER. Required on the header; it is not inferred from the URL. Lines inherit it.
amount_txndecimalRecommendedAmount paid, as a negative number on the header (money out).
amount_netdecimalRecommendedNet amount, also negative.
amount_signumdecimalRequired1 on the payment voucher header. Validated on the header only.
amount_internal_settlementdecimalServer-maintainedAmount applied against outstanding documents.
amount_open_balancedecimalServer-maintainedRemaining unapplied amount.
arap_stlm_amount, arap_doc_open, arap_baldecimalServer-maintainedAR/AP settlement tracking.
posting_statusstringOptionalDRAFT or FINAL.
posting_cashbook, posting_journalstringServer-maintainedWhether each posting has run.
statusstringOptionalDefaults to ACTIVE.
revisionUUIDOptionalGenerated if omitted. Send the value you read back when updating.
client_key, client_sourcestringOptionalYour system’s identifiers.
client_doc_1client_doc_5stringOptionalYour own document references.
property_jsonobjectOptionalArbitrary extra properties.
server_doc_1server_doc_5stringServer-assignedRunning numbers generated by BigLedger.
pin_code, pin_type, pin_hash, pin_algorithmstringServer-assignedGenerated 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": { } }
FieldTypeDescription
guidUUIDGenerated if omitted.
guid_doc_1_hdrUUIDRequired. One of the two documents.
server_doc_type_doc_1stringIts server_doc_type, upper-case form. Recommended.
guid_doc_2_hdrUUIDRequired. The other document.
server_doc_type_doc_2stringIts server_doc_type, upper-case form. Recommended.
amount_contradecimalRequired. Amount applied between the two.
date_txn, date_doc_1, date_doc_2datetimeOptional dates.
statusstringDefaults to ACTIVE.
revisionUUIDGenerated if omitted.
posting_status, posting_journal, posting_arapstringPosting state.
forex_doc_hdr_guid, forex_gain_loss_baseUUID / decimalForeign-exchange gain or loss, where relevant.
doc_remarksstringOptional remarks.
client_source, gen_doc_client_key_1, gen_doc_client_value_1, gen_doc_client_key_2, gen_doc_client_value_2stringYour 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:

ValueMeaning
DRAFTCreated but not posted. Freely editable.
FINALPosted. 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-ep

The 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/query

Takes 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"
Last updated on