Internal GL counterparty
Use counterpartyType: "INTERNAL_GL" when the money goes into, or comes out of, one of your own general ledger
accounts: charges, fees, commissions, loan repayments, cash deposits to a till GL, and similar postings.
accountName is required, even though a GL is usually identified by its code. A counterparty with only glCode is
rejected with counterparty.accountName is required for this counterparty type. Put the GL's display name in
accountName.
| Field | Required | What it means | Why it matters for monitoring |
|---|---|---|---|
accountName | Yes | The GL's display name, such as Account maintenance fee income. | Shown to analysts. |
glCode | No, but strongly recommended | The GL code receiving or sending the money. | GL rules match on it, and it can match a GL code on your blacklist. |
accountNumber | No | An account number tied to the GL, if your core banking system uses one. | Can match your blacklist, and supports velocity rules. |
A customer paying a charge into an income GL
Your core banking system debits a customer's account for a monthly account maintenance fee and credits the fee income GL.
POST /api/transactions
Authorization: Bearer <oneview-service-account-api-key>
Content-Type: application/json
{
"transactionReference": "CHG-20260930-100231",
"direction": "OUTBOUND",
"accountHolderType": "CUSTOMER",
"paymentMethod": "INTERNAL_TRANSFER",
"channel": "CORE_BANKING",
"status": "POSTED",
"isInternal": true,
"isGlTransaction": true,
"isCrossBorder": false,
"amount": "1000.00",
"currency": "NGN",
"taxAmount": "75.00",
"narration": "Account maintenance fee September",
"executedAt": "2026-09-30T23:15:00Z",
"accountHolder": {
"customerUniqueId": "CUS-100231",
"accountNumber": "0012345678",
"accountName": "Ada Demo Okafor"
},
"counterparty": {
"counterpartyType": "INTERNAL_GL",
"accountName": "Account maintenance fee income",
"glCode": "40250"
},
"ledgerPostings": [
{
"postingId": "CHG-20260930-100231-1",
"glCode": "20100",
"glName": "Customer savings deposits",
"entryType": "DEBIT",
"amount": "1075.00",
"currency": "NGN",
"accountNumber": "0012345678"
},
{
"postingId": "CHG-20260930-100231-2",
"glCode": "40250",
"glName": "Account maintenance fee income",
"entryType": "CREDIT",
"amount": "1000.00",
"currency": "NGN"
},
{
"postingId": "CHG-20260930-100231-3",
"glCode": "25010",
"glName": "VAT payable",
"entryType": "CREDIT",
"amount": "75.00",
"currency": "NGN"
}
]
}
| Field | What it means | Why it matters for monitoring |
|---|---|---|
accountHolderType | CUSTOMER, because the charge is posted to the customer's account. | The activity is attributed to that customer. |
direction | OUTBOUND: money leaves the customer's account. | Charges count towards the customer's outgoing activity. |
amount | The charge itself, 1000.00. | When the transaction is the charge, put the charge in amount. Use feeAmount only for a fee added on top of another transaction, so the same money is not counted twice. |
taxAmount | VAT on the charge, 75.00. | Kept apart from the charge. |
isInternal | true: the money stays within the institution. | Separates internal postings from money leaving the bank. |
channel | CORE_BANKING, because the system posted it rather than the customer. | Rules on system-initiated activity. |
ledgerPostings | The customer deposit GL is debited 1075.00, fee income is credited 1000.00 and VAT payable 75.00. | The legs balance, and each GL can be inspected by rules. |
The same pattern works in reverse. For example, a refund from an income GL back to a customer is an INBOUND
transaction for the customer, with the income GL as the INTERNAL_GL counterparty. When one of your GLs starts the
transaction instead of a customer, see Internal GL account holder.
OneView does not enforce that a journal balances. The legs above happen to balance, but OneView does not check this — it accepts and stores a
ledgerPostingsarray whose debits and credits differ. Only a rule your administrator configures to compare the legs can catch an unbalanced journal. See Internal GL account holder for the full leg format rules.
Response
This is the response to the account maintenance fee charge above:
{
"status": true,
"message": "Transaction evaluated",
"data": {
"transaction": {
"id": "2f8b4a61-9d3e-4c70-a516-3e8c0b5f2a94",
"transactionReference": "CHG-20260930-100231",
"direction": "OUTBOUND",
"receivedAt": "2026-09-30T23:15:00.187Z",
"replayed": false
},
"decision": {
"outcome": "PASS",
"riskScore": 0,
"evaluatedAt": "2026-09-30T23:15:00.199Z",
"evaluationMs": 6.028,
"complete": true,
"rulesEvaluated": 18,
"rulesetSnapshot": "9ffa3b395a9799b1a1104ab1b536ed1667b487510829ceefc27593941fafb35e",
"gradingVersion": 3,
"triggeredRules": []
}
}
}
Status is 201 for a new transaction, 200 for a replay. See Decision responses for every
outcome.
Errors specific to an internal GL counterparty
| Cause | field | code | message |
|---|---|---|---|
No accountName, even with glCode present | counterparty | required | counterparty.accountName is required for this counterparty type |
A ledger leg has no glCode | ledgerPostings.0 | required | ledgerPostings.0.glCode is required |
See Errors for the complete catalogue.
Idempotency
Deduplication is by transactionReference and direction, including the full ledgerPostings array. Resubmitting
the identical body returns 200 with replayed: true and does not re-post the charge or the ledger legs a second
time. A different body under the same reference and direction, for example a corrected taxAmount, is rejected
with 409 IDEMPOTENCY_CONFLICT — use a new reference for a genuinely new charge. See Idempotency in
Submitting transactions.
GL display names are screened like any other name
PEP and sanction screening resolves a counterparty's name from firstName/lastName, companyName, then
accountName — see Customer account holder.
Unlike INTERNAL_GL as an account holder (never screened by name, since none of its fields are in that list —
see Internal GL account holder), an
INTERNAL_GL counterparty always has accountName, because it is required. That value — a ledger display name
such as "Account maintenance fee income", not a person's name — is sent to PEP and sanction screening the same
way any other counterparty name would be. In practice a GL label is very unlikely to match a real screening list,
but it does consume a screening call and could, in principle, produce a false-positive match your analysts would
need to clear.